summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/passes/InstrumentLocals.cpp2
-rw-r--r--src/passes/InstrumentMemory.cpp143
2 files changed, 93 insertions, 52 deletions
diff --git a/src/passes/InstrumentLocals.cpp b/src/passes/InstrumentLocals.cpp
index a1835eb64..6b44af0ad 100644
--- a/src/passes/InstrumentLocals.cpp
+++ b/src/passes/InstrumentLocals.cpp
@@ -129,7 +129,7 @@ private:
void addImport(Module* wasm, Name name, std::string sig) {
auto import = new Function;
import->name = name;
- import->module = INSTRUMENT;
+ import->module = ENV;
import->base = name;
auto* functionType = ensureFunctionType(sig, wasm);
import->type = functionType->name;
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index 17b5850f4..a929478df 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -18,27 +18,21 @@
// Instruments the build with code to intercept all memory reads and writes.
// This can be useful in building tools that analyze memory access behaviour.
//
-// The instrumentation is performed by calling an FFI with an ID for each
-// memory access site. Load / store IDs share the same index space. The
-// instrumentation wraps the evaluation of the address operand, therefore
-// it executes before the load / store is executed. Note that Instrumentation
-// code must return tha address argument.
-//
-// Loads: load(id, bytes, offset, address) => address
-//
// Before:
// (i32.load8_s align=1 offset=2 (i32.const 3))
//
// After:
-// (i32.load8_s align=1 offset=2
-// (call $load
-// (i32.const n) // ID
-// (i32.const 1) // bytes
-// (i32.const 2) // offset
-// (i32.const 3) // address
+// (call $load_val_i32
+// (i32.const n) // ID
+// (i32.load8_s align=1 offset=2
+// (call $load_ptr
+// (i32.const n) // ID
+// (i32.const 1) // bytes
+// (i32.const 2) // offset
+// (i32.const 3) // address
+// )
// )
// )
-//
// Stores: store(id, bytes, offset, address) => address
//
// Before:
@@ -46,13 +40,16 @@
//
// After:
// (i32.store16 align=1 offset=2
-// (call $store
+// (call $store_ptr
// (i32.const n) // ID
// (i32.const 1) // bytes
// (i32.const 2) // offset
// (i32.const 3) // address
// )
-// (i32.const 4)
+// (call $store_val_i32
+// (i32.const n) // ID
+// (i32.const 4)
+// )
// )
#include <wasm.h>
@@ -65,57 +62,101 @@
namespace wasm {
-Name load("load");
-Name store("store");
+static Name load_ptr("load_ptr"),
+ load_val_i32("load_val_i32"),
+ load_val_i64("load_val_i64"),
+ load_val_f32("load_val_f32"),
+ load_val_f64("load_val_f64"),
+ store_ptr("store_ptr"),
+ store_val_i32("store_val_i32"),
+ store_val_i64("store_val_i64"),
+ store_val_f32("store_val_f32"),
+ store_val_f64("store_val_f64");
+
// TODO: Add support for atomicRMW/cmpxchg
struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
void visitLoad(Load* curr) {
- makeLoadCall(curr);
- }
- void visitStore(Store* curr) {
- makeStoreCall(curr);
- }
- void addImport(Module *curr, Name name, std::string sig) {
- auto import = new Function;
- import->name = name;
- import->module = INSTRUMENT;
- import->base = name;
- auto* functionType = ensureFunctionType(sig, curr);
- import->type = functionType->name;
- FunctionTypeUtils::fillFunction(import, functionType);
- curr->addFunction(import);
- }
-
- void visitModule(Module *curr) {
- addImport(curr, load, "iiiii");
- addImport(curr, store, "iiiii");
- }
-
-private:
- std::atomic<Index> id;
- Expression* makeLoadCall(Load* curr) {
+ id++;
Builder builder(*getModule());
- curr->ptr = builder.makeCall(load,
- { builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
+ curr->ptr = builder.makeCall(load_ptr,
+ {
+ builder.makeConst(Literal(int32_t(id))),
builder.makeConst(Literal(int32_t(curr->bytes))),
builder.makeConst(Literal(int32_t(curr->offset.addr))),
- curr->ptr},
+ curr->ptr
+ },
i32
);
- return curr;
+ Name target;
+ switch (curr->type) {
+ case i32: target = load_val_i32; break;
+ case i64: target = load_val_i64; break;
+ case f32: target = load_val_f32; break;
+ case f64: target = load_val_f64; break;
+ default: return; // TODO: other types, unreachable, etc.
+ }
+ replaceCurrent(builder.makeCall(target,
+ {
+ builder.makeConst(Literal(int32_t(id))),
+ curr
+ },
+ curr->type
+ ));
}
- Expression* makeStoreCall(Store* curr) {
+ void visitStore(Store* curr) {
+ id++;
Builder builder(*getModule());
- curr->ptr = builder.makeCall(store,
- { builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
+ curr->ptr = builder.makeCall(store_ptr,
+ { builder.makeConst(Literal(int32_t(id))),
builder.makeConst(Literal(int32_t(curr->bytes))),
builder.makeConst(Literal(int32_t(curr->offset.addr))),
curr->ptr },
i32
);
- return curr;
+ Name target;
+ switch (curr->value->type) {
+ case i32: target = store_val_i32; break;
+ case i64: target = store_val_i64; break;
+ case f32: target = store_val_f32; break;
+ case f64: target = store_val_f64; break;
+ default: return; // TODO: other types, unreachable, etc.
+ }
+ curr->value = builder.makeCall(target,
+ {
+ builder.makeConst(Literal(int32_t(id))),
+ curr->value
+ },
+ curr->value->type
+ );
+ }
+
+ void visitModule(Module *curr) {
+ addImport(curr, load_ptr, "iiiii");
+ addImport(curr, load_val_i32, "iii");
+ addImport(curr, load_val_i64, "jij");
+ addImport(curr, load_val_f32, "fif");
+ addImport(curr, load_val_f64, "did");
+ addImport(curr, store_ptr, "iiiii");
+ addImport(curr, store_val_i32, "iii");
+ addImport(curr, store_val_i64, "jij");
+ addImport(curr, store_val_f32, "fif");
+ addImport(curr, store_val_f64, "did");
+ }
+
+private:
+ Index id;
+
+ void addImport(Module *curr, Name name, std::string sig) {
+ auto import = new Function;
+ import->name = name;
+ import->module = ENV;
+ import->base = name;
+ auto* functionType = ensureFunctionType(sig, curr);
+ import->type = functionType->name;
+ FunctionTypeUtils::fillFunction(import, functionType);
+ curr->addFunction(import);
}
};