Skip to content

Commit b9bf2ee

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 b9bf2ee

File tree

5 files changed

+663
-193
lines changed

5 files changed

+663
-193
lines changed

src/passes/InstrumentMemory.cpp

Lines changed: 92 additions & 4 deletions
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 (!checkExpression(expr)) { \
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(curr);
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(curr);
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(curr);
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(curr);
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(curr);
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(curr);
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(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+
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,14 +341,61 @@ 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), {});
307349
import->module = ENV;
308350
import->base = name;
309351
curr->addFunction(std::move(import));
310352
}
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+
}
311399
};
312400

313401
Pass* createInstrumentMemoryPass() { return new InstrumentMemory(); }

0 commit comments

Comments
 (0)