59
59
60
60
#include " asmjs/shared-constants.h"
61
61
#include " shared-constants.h"
62
+ #include " support/string.h"
62
63
#include < pass.h>
63
64
#include < wasm-builder.h>
64
65
#include < wasm.h>
@@ -93,14 +94,26 @@ static Name array_set_val_f32("array_set_val_f32");
93
94
static Name array_set_val_f64 (" array_set_val_f64" );
94
95
static Name array_get_index (" array_get_index" );
95
96
static Name array_set_index (" array_set_index" );
97
+ static Name memory_grow_pre (" memory_grow_pre" );
98
+ static Name memory_grow_post (" memory_grow_post" );
96
99
97
100
// TODO: Add support for atomicRMW/cmpxchg
98
101
99
- struct InstrumentMemory : public WalkerPass <PostWalker<InstrumentMemory>> {
100
- // Adds calls to new imports.
101
- bool addsEffects () override { return true ; }
102
+ using InstructionFilter = std::optional<std::unordered_set<std::string>>;
103
+
104
+ #define CHECK_EXPRESSION (expr ) \
105
+ do { \
106
+ if (!checkExpression (expr)) { \
107
+ return ; \
108
+ } \
109
+ } while (false )
102
110
111
+ struct AddInstrumentation : public WalkerPass <PostWalker<AddInstrumentation>> {
112
+ explicit AddInstrumentation (InstructionFilter filter)
113
+ : _filter(std::move(filter)) {}
103
114
void visitLoad (Load* curr) {
115
+ CHECK_EXPRESSION (curr);
116
+
104
117
id++;
105
118
Builder builder (*getModule ());
106
119
auto mem = getModule ()->getMemory (curr->memory );
@@ -134,6 +147,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
134
147
}
135
148
136
149
void visitStore (Store* curr) {
150
+ CHECK_EXPRESSION (curr);
151
+
137
152
id++;
138
153
Builder builder (*getModule ());
139
154
auto mem = getModule ()->getMemory (curr->memory );
@@ -167,6 +182,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
167
182
}
168
183
169
184
void visitStructGet (StructGet* curr) {
185
+ CHECK_EXPRESSION (curr);
186
+
170
187
Builder builder (*getModule ());
171
188
Name target;
172
189
if (curr->type == Type::i32) {
@@ -185,6 +202,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
185
202
}
186
203
187
204
void visitStructSet (StructSet* curr) {
205
+ CHECK_EXPRESSION (curr);
206
+
188
207
Builder builder (*getModule ());
189
208
Name target;
190
209
if (curr->value ->type == Type::i32) {
@@ -205,6 +224,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
205
224
}
206
225
207
226
void visitArrayGet (ArrayGet* curr) {
227
+ CHECK_EXPRESSION (curr);
228
+
208
229
Builder builder (*getModule ());
209
230
curr->index =
210
231
builder.makeCall (array_get_index,
@@ -227,6 +248,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
227
248
}
228
249
229
250
void visitArraySet (ArraySet* curr) {
251
+ CHECK_EXPRESSION (curr);
252
+
230
253
Builder builder (*getModule ());
231
254
curr->index =
232
255
builder.makeCall (array_set_index,
@@ -250,10 +273,28 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
250
273
curr->value ->type );
251
274
}
252
275
276
+ void visitMemoryGrow (MemoryGrow* curr) {
277
+ CHECK_EXPRESSION (curr);
278
+
279
+ id++;
280
+ Builder builder (*getModule ());
281
+ auto addressType = getModule ()->getMemory (curr->memory )->addressType ;
282
+ curr->delta =
283
+ builder.makeCall (memory_grow_pre,
284
+ {builder.makeConst (int32_t (id)), curr->delta },
285
+ addressType);
286
+ replaceCurrent (builder.makeCall (
287
+ memory_grow_post, {builder.makeConst (int32_t (id)), curr}, addressType));
288
+ }
289
+
253
290
void visitModule (Module* curr) {
254
291
auto addressType =
255
292
curr->memories .empty () ? Type::i32 : curr->memories [0 ]->addressType ;
256
293
294
+ // Grow.
295
+ addImport (curr, memory_grow_pre, {Type::i32, addressType}, addressType);
296
+ addImport (curr, memory_grow_post, {Type::i32, addressType}, addressType);
297
+
257
298
// Load.
258
299
addImport (curr,
259
300
load_ptr,
@@ -300,14 +341,61 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
300
341
}
301
342
302
343
private:
303
- Index id;
344
+ Index id = 0 ;
345
+ InstructionFilter _filter;
304
346
305
347
void addImport (Module* curr, Name name, Type params, Type results) {
306
348
auto import = Builder::makeFunction (name, Signature (params, results), {});
307
349
import->module = ENV;
308
350
import->base = name;
309
351
curr->addFunction (std::move (import));
310
352
}
353
+
354
+ template <typename T> bool checkExpression (T* expr) {
355
+ if (_filter.has_value ()) {
356
+ return _filter->count (expressionToString (expr)) > 0 ;
357
+ }
358
+ return true ;
359
+ }
360
+
361
+ std::string loadStoreTypeToString (Type type) { return type.toString (); }
362
+
363
+ std::string expressionToString (Load* expr) {
364
+ const auto suffix =
365
+ (expr->bytes == expr->type .getByteSize ()
366
+ ? " "
367
+ : std::to_string (expr->bytes * 8 ) + " _" + (expr->signed_ ? ' s' : ' u' ));
368
+
369
+ return expr->type .toString () + " .load" + suffix;
370
+ }
371
+
372
+ std::string expressionToString (Store* expr) {
373
+ const auto suffix = expr->bytes == expr->valueType .getByteSize ()
374
+ ? " "
375
+ : std::to_string (expr->bytes * 8 );
376
+
377
+ return expr->valueType .toString () + " .store" + suffix;
378
+ }
379
+
380
+ std::string expressionToString (StructGet* expr) { return " struct.get" ; }
381
+ std::string expressionToString (StructSet* expr) { return " struct.set" ; }
382
+ std::string expressionToString (ArrayGet* expr) { return " array.get" ; }
383
+ std::string expressionToString (ArraySet* expr) { return " array.set" ; }
384
+ std::string expressionToString (MemoryGrow* expr) { return " memory.grow" ; }
385
+ };
386
+ struct InstrumentMemory : Pass {
387
+ // Adds calls to new imports.
388
+ bool addsEffects () override { return true ; }
389
+
390
+ void run (Module* module) override {
391
+ auto arg = getArgumentOrDefault (" instrument-memory" , " " );
392
+ InstructionFilter instructions = std::nullopt;
393
+ if (arg.size () > 0 ) {
394
+ String::Split s (arg, " ," );
395
+ instructions = std::unordered_set<std::string>{s.begin (), s.end ()};
396
+ }
397
+ AddInstrumentation (std::move (instructions)).run (getPassRunner (), module);
398
+ }
311
399
};
312
400
313
401
Pass* createInstrumentMemoryPass () { return new InstrumentMemory (); }
0 commit comments