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 (filter.has_value () && filter->count (expr) == 0 ) { \
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 (" load" );
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 (" store" );
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 (" struct.get" );
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 (" struct.set" );
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 (" array.get" );
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 (" array.set" );
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 (" memory.grow" );
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,7 +341,8 @@ 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), {});
@@ -309,6 +351,20 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
309
351
curr->addFunction (std::move (import));
310
352
}
311
353
};
354
+ struct InstrumentMemory : Pass {
355
+ // Adds calls to new imports.
356
+ bool addsEffects () override { return true ; }
357
+
358
+ void run (Module* module) override {
359
+ auto arg = getArgumentOrDefault (" instrument-memory" , " " );
360
+ InstructionFilter instructions = std::nullopt;
361
+ if (arg.size () > 0 ) {
362
+ String::Split s (arg, " ," );
363
+ instructions = std::unordered_set<std::string>{s.begin (), s.end ()};
364
+ }
365
+ AddInstrumentation (std::move (instructions)).run (getPassRunner (), module);
366
+ }
367
+ };
312
368
313
369
Pass* createInstrumentMemoryPass () { return new InstrumentMemory (); }
314
370
0 commit comments