summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2021-07-15 10:26:59 -0700
committerGitHub <noreply@github.com>2021-07-15 10:26:59 -0700
commit27831cba47722c10a8a6f412d56665a4e7074540 (patch)
treef93c1909477ad3ee1dd2dd612732d722b7ff77a3 /src
parenta3d6930e59114196f29cb3318e96843dbd0b413c (diff)
downloadbinaryen-27831cba47722c10a8a6f412d56665a4e7074540.tar.gz
binaryen-27831cba47722c10a8a6f412d56665a4e7074540.tar.bz2
binaryen-27831cba47722c10a8a6f412d56665a4e7074540.zip
[Wasm GC] Add Wasm GC support to InstrumentMemory (#3976)
This adds calls to imports around every struct load and store, to note their values, and also to arrays (where it also notes the index). This has been very useful in debugging LowerGC (lowering of Wasm GC to wasm MVP).
Diffstat (limited to 'src')
-rw-r--r--src/passes/InstrumentMemory.cpp135
1 files changed, 135 insertions, 0 deletions
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
index 38a23a658..073c78822 100644
--- a/src/passes/InstrumentMemory.cpp
+++ b/src/passes/InstrumentMemory.cpp
@@ -51,6 +51,11 @@
// (i32.const 4)
// )
// )
+//
+// GC struct and array operations are similarly instrumented, but without their
+// pointers (which are references), and we only log MVP wasm types (i.e., not
+// references or rtts).
+//
#include "asmjs/shared-constants.h"
#include "shared-constants.h"
@@ -70,6 +75,24 @@ static Name store_val_i32("store_val_i32");
static Name store_val_i64("store_val_i64");
static Name store_val_f32("store_val_f32");
static Name store_val_f64("store_val_f64");
+static Name struct_get_val_i32("struct_get_val_i32");
+static Name struct_get_val_i64("struct_get_val_i64");
+static Name struct_get_val_f32("struct_get_val_f32");
+static Name struct_get_val_f64("struct_get_val_f64");
+static Name struct_set_val_i32("struct_set_val_i32");
+static Name struct_set_val_i64("struct_set_val_i64");
+static Name struct_set_val_f32("struct_set_val_f32");
+static Name struct_set_val_f64("struct_set_val_f64");
+static Name array_get_val_i32("array_get_val_i32");
+static Name array_get_val_i64("array_get_val_i64");
+static Name array_get_val_f32("array_get_val_f32");
+static Name array_get_val_f64("array_get_val_f64");
+static Name array_set_val_i32("array_set_val_i32");
+static Name array_set_val_i64("array_set_val_i64");
+static Name array_set_val_f32("array_set_val_f32");
+static Name array_set_val_f64("array_set_val_f64");
+static Name array_get_index("array_get_index");
+static Name array_set_index("array_set_index");
// TODO: Add support for atomicRMW/cmpxchg
@@ -138,20 +161,132 @@ struct InstrumentMemory : public WalkerPass<PostWalker<InstrumentMemory>> {
target, {builder.makeConst(int32_t(id)), curr->value}, curr->value->type);
}
+ void visitStructGet(StructGet* curr) {
+ Builder builder(*getModule());
+ Name target;
+ if (curr->type == Type::i32) {
+ target = struct_get_val_i32;
+ } else if (curr->type == Type::i64) {
+ target = struct_get_val_i64;
+ } else if (curr->type == Type::f32) {
+ target = struct_get_val_f32;
+ } else if (curr->type == Type::f64) {
+ target = struct_get_val_f64;
+ } else {
+ return; // TODO: other types, unreachable, etc.
+ }
+ replaceCurrent(builder.makeCall(
+ target, {builder.makeConst(int32_t(id++)), curr}, curr->type));
+ }
+
+ void visitStructSet(StructSet* curr) {
+ Builder builder(*getModule());
+ Name target;
+ if (curr->value->type == Type::i32) {
+ target = struct_set_val_i32;
+ } else if (curr->value->type == Type::i64) {
+ target = struct_set_val_i64;
+ } else if (curr->value->type == Type::f32) {
+ target = struct_set_val_f32;
+ } else if (curr->value->type == Type::f64) {
+ target = struct_set_val_f64;
+ } else {
+ return; // TODO: other types, unreachable, etc.
+ }
+ curr->value =
+ builder.makeCall(target,
+ {builder.makeConst(int32_t(id++)), curr->value},
+ curr->value->type);
+ }
+
+ void visitArrayGet(ArrayGet* curr) {
+ Builder builder(*getModule());
+ curr->index =
+ builder.makeCall(array_get_index,
+ {builder.makeConst(int32_t(id++)), curr->index},
+ Type::i32);
+ Name target;
+ if (curr->type == Type::i32) {
+ target = array_get_val_i32;
+ } else if (curr->type == Type::i64) {
+ target = array_get_val_i64;
+ } else if (curr->type == Type::f32) {
+ target = array_get_val_f32;
+ } else if (curr->type == Type::f64) {
+ target = array_get_val_f64;
+ } else {
+ return; // TODO: other types, unreachable, etc.
+ }
+ replaceCurrent(builder.makeCall(
+ target, {builder.makeConst(int32_t(id++)), curr}, curr->type));
+ }
+
+ void visitArraySet(ArraySet* curr) {
+ Builder builder(*getModule());
+ curr->index =
+ builder.makeCall(array_set_index,
+ {builder.makeConst(int32_t(id++)), curr->index},
+ Type::i32);
+ Name target;
+ if (curr->value->type == Type::i32) {
+ target = array_set_val_i32;
+ } else if (curr->value->type == Type::i64) {
+ target = array_set_val_i64;
+ } else if (curr->value->type == Type::f32) {
+ target = array_set_val_f32;
+ } else if (curr->value->type == Type::f64) {
+ target = array_set_val_f64;
+ } else {
+ return; // TODO: other types, unreachable, etc.
+ }
+ curr->value =
+ builder.makeCall(target,
+ {builder.makeConst(int32_t(id++)), curr->value},
+ curr->value->type);
+ }
+
void visitModule(Module* curr) {
auto indexType = curr->memory.indexType;
+
+ // Load.
addImport(
curr, load_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
addImport(curr, load_val_i32, {Type::i32, Type::i32}, Type::i32);
addImport(curr, load_val_i64, {Type::i32, Type::i64}, Type::i64);
addImport(curr, load_val_f32, {Type::i32, Type::f32}, Type::f32);
addImport(curr, load_val_f64, {Type::i32, Type::f64}, Type::f64);
+
+ // Store.
addImport(
curr, store_ptr, {Type::i32, Type::i32, indexType, indexType}, indexType);
addImport(curr, store_val_i32, {Type::i32, Type::i32}, Type::i32);
addImport(curr, store_val_i64, {Type::i32, Type::i64}, Type::i64);
addImport(curr, store_val_f32, {Type::i32, Type::f32}, Type::f32);
addImport(curr, store_val_f64, {Type::i32, Type::f64}, Type::f64);
+
+ if (curr->features.hasGC()) {
+ // Struct get/set.
+ addImport(curr, struct_get_val_i32, {Type::i32, Type::i32}, Type::i32);
+ addImport(curr, struct_get_val_i64, {Type::i32, Type::i64}, Type::i64);
+ addImport(curr, struct_get_val_f32, {Type::i32, Type::f32}, Type::f32);
+ addImport(curr, struct_get_val_f64, {Type::i32, Type::f64}, Type::f64);
+ addImport(curr, struct_set_val_i32, {Type::i32, Type::i32}, Type::i32);
+ addImport(curr, struct_set_val_i64, {Type::i32, Type::i64}, Type::i64);
+ addImport(curr, struct_set_val_f32, {Type::i32, Type::f32}, Type::f32);
+ addImport(curr, struct_set_val_f64, {Type::i32, Type::f64}, Type::f64);
+
+ // Array get/set.
+ addImport(curr, array_get_val_i32, {Type::i32, Type::i32}, Type::i32);
+ addImport(curr, array_get_val_i64, {Type::i32, Type::i64}, Type::i64);
+ addImport(curr, array_get_val_f32, {Type::i32, Type::f32}, Type::f32);
+ addImport(curr, array_get_val_f64, {Type::i32, Type::f64}, Type::f64);
+ addImport(curr, array_set_val_i32, {Type::i32, Type::i32}, Type::i32);
+ addImport(curr, array_set_val_i64, {Type::i32, Type::i64}, Type::i64);
+ addImport(curr, array_set_val_f32, {Type::i32, Type::f32}, Type::f32);
+ addImport(curr, array_set_val_f64, {Type::i32, Type::f64}, Type::f64);
+ addImport(curr, array_get_index, {Type::i32, Type::i32}, Type::i32);
+ addImport(curr, array_set_index, {Type::i32, Type::i32}, Type::i32);
+ }
}
private: