Skip to content

Commit 2dc6c17

Browse files
committed
Update InstrumentMemory pass to support memory.grow instructions
Also added instruction filter that allows to limit instrumented instructions.
1 parent a4966d7 commit 2dc6c17

File tree

5 files changed

+839
-193
lines changed

5 files changed

+839
-193
lines changed

src/passes/InstrumentMemory.cpp

+60-4
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060
#include "asmjs/shared-constants.h"
6161
#include "shared-constants.h"
62+
#include "support/string.h"
6263
#include <pass.h>
6364
#include <wasm-builder.h>
6465
#include <wasm.h>
@@ -93,14 +94,26 @@ static Name array_set_val_f32("array_set_val_f32");
9394
static Name array_set_val_f64("array_set_val_f64");
9495
static Name array_get_index("array_get_index");
9596
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");
9699

97100
// TODO: Add support for atomicRMW/cmpxchg
98101

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)
102110

111+
struct AddInstrumentation : public WalkerPass<PostWalker<AddInstrumentation>> {
112+
explicit AddInstrumentation(InstructionFilter filter)
113+
: filter(std::move(filter)) {}
103114
void visitLoad(Load* curr) {
115+
CHECK_EXPRESSION("load");
116+
104117
id++;
105118
Builder builder(*getModule());
106119
auto mem = getModule()->getMemory(curr->memory);
@@ -134,6 +147,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
134147
}
135148

136149
void visitStore(Store* curr) {
150+
CHECK_EXPRESSION("store");
151+
137152
id++;
138153
Builder builder(*getModule());
139154
auto mem = getModule()->getMemory(curr->memory);
@@ -167,6 +182,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
167182
}
168183

169184
void visitStructGet(StructGet* curr) {
185+
CHECK_EXPRESSION("struct.get");
186+
170187
Builder builder(*getModule());
171188
Name target;
172189
if (curr->type == Type::i32) {
@@ -185,6 +202,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
185202
}
186203

187204
void visitStructSet(StructSet* curr) {
205+
CHECK_EXPRESSION("struct.set");
206+
188207
Builder builder(*getModule());
189208
Name target;
190209
if (curr->value->type == Type::i32) {
@@ -205,6 +224,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
205224
}
206225

207226
void visitArrayGet(ArrayGet* curr) {
227+
CHECK_EXPRESSION("array.get");
228+
208229
Builder builder(*getModule());
209230
curr->index =
210231
builder.makeCall(array_get_index,
@@ -227,6 +248,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
227248
}
228249

229250
void visitArraySet(ArraySet* curr) {
251+
CHECK_EXPRESSION("array.set");
252+
230253
Builder builder(*getModule());
231254
curr->index =
232255
builder.makeCall(array_set_index,
@@ -250,10 +273,28 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
250273
curr->value->type);
251274
}
252275

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+
253290
void visitModule(Module* curr) {
254291
auto addressType =
255292
curr->memories.empty() ? Type::i32 : curr->memories[0]->addressType;
256293

294+
// Grow.
295+
addImport(curr, memory_grow_pre, {Type::i32, addressType}, addressType);
296+
addImport(curr, memory_grow_post, {Type::i32, addressType}, addressType);
297+
257298
// Load.
258299
addImport(curr,
259300
load_ptr,
@@ -300,7 +341,8 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
300341
}
301342

302343
private:
303-
Index id;
344+
Index id = 0;
345+
InstructionFilter filter;
304346

305347
void addImport(Module* curr, Name name, Type params, Type results) {
306348
auto import = Builder::makeFunction(name, Signature(params, results), {});
@@ -309,6 +351,20 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
309351
curr->addFunction(std::move(import));
310352
}
311353
};
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+
};
312368

313369
Pass* createInstrumentMemoryPass() { return new InstrumentMemory(); }
314370

0 commit comments

Comments
 (0)