summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/asmjs/shared-constants.cpp1
-rw-r--r--src/asmjs/shared-constants.h1
-rw-r--r--src/passes/CMakeLists.txt1
-rw-r--r--src/passes/InstrumentMemory.cpp123
-rw-r--r--src/passes/pass.cpp1
-rw-r--r--src/passes/passes.h1
6 files changed, 128 insertions, 0 deletions
diff --git a/src/asmjs/shared-constants.cpp b/src/asmjs/shared-constants.cpp
index d704c8009..02e80d36b 100644
--- a/src/asmjs/shared-constants.cpp
+++ b/src/asmjs/shared-constants.cpp
@@ -55,6 +55,7 @@ cashew::IString GLOBAL("global"),
USE_ASM("use asm"),
BUFFER("buffer"),
ENV("env"),
+ INSTRUMENT("instrument"),
MATH_IMUL("Math_imul"),
MATH_CLZ32("Math_clz32"),
MATH_CTZ32("Math_ctz32"),
diff --git a/src/asmjs/shared-constants.h b/src/asmjs/shared-constants.h
index 7b48c3df5..f13023778 100644
--- a/src/asmjs/shared-constants.h
+++ b/src/asmjs/shared-constants.h
@@ -58,6 +58,7 @@ extern cashew::IString GLOBAL,
USE_ASM,
BUFFER,
ENV,
+ INSTRUMENT,
MATH_IMUL,
MATH_CLZ32,
MATH_CTZ32,
diff --git a/src/passes/CMakeLists.txt b/src/passes/CMakeLists.txt
index 75e634c16..637f40d94 100644
--- a/src/passes/CMakeLists.txt
+++ b/src/passes/CMakeLists.txt
@@ -9,6 +9,7 @@ SET(passes_SOURCES
LegalizeJSInterface.cpp
LocalCSE.cpp
LogExecution.cpp
+ InstrumentMemory.cpp
MemoryPacking.cpp
MergeBlocks.cpp
Metrics.cpp
diff --git a/src/passes/InstrumentMemory.cpp b/src/passes/InstrumentMemory.cpp
new file mode 100644
index 000000000..536031064
--- /dev/null
+++ b/src/passes/InstrumentMemory.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2017 WebAssembly Community Group participants
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//
+// 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
+// )
+// )
+//
+// Stores: store(id, bytes, offset, address) => address
+//
+// Before:
+// (i32.store8 align=1 offset=2 (i32.const 3) (i32.const 4))
+//
+// After:
+// (i32.store16 align=1 offset=2
+// (call $store
+// (i32.const n) // ID
+// (i32.const 1) // bytes
+// (i32.const 2) // offset
+// (i32.const 3) // address
+// )
+// (i32.const 4)
+// )
+
+#include <wasm.h>
+#include <wasm-builder.h>
+#include <pass.h>
+#include "shared-constants.h"
+#include "asmjs/shared-constants.h"
+#include "asm_v_wasm.h"
+
+namespace wasm {
+
+Name load("load");
+Name store("store");
+
+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 Import;
+ import->name = name;
+ import->module = INSTRUMENT;
+ import->base = name;
+ import->functionType = ensureFunctionType(sig, curr)->name;
+ import->kind = ExternalKind::Function;
+ curr->addImport(import);
+ }
+
+ void visitModule(Module *curr) {
+ addImport(curr, load, "iiiii");
+ addImport(curr, store, "iiiii");
+ }
+
+private:
+ std::atomic<Index> id;
+ Expression* makeLoadCall(Load* curr) {
+ Builder builder(*getModule());
+ curr->ptr = builder.makeCallImport(load,
+ { builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
+ builder.makeConst(Literal(int32_t(curr->bytes))),
+ builder.makeConst(Literal(int32_t(curr->offset.addr))),
+ curr->ptr},
+ i32
+ );
+ return curr;
+ }
+
+ Expression* makeStoreCall(Store* curr) {
+ Builder builder(*getModule());
+ curr->ptr = builder.makeCallImport(store,
+ { builder.makeConst(Literal(int32_t(id.fetch_add(1)))),
+ builder.makeConst(Literal(int32_t(curr->bytes))),
+ builder.makeConst(Literal(int32_t(curr->offset.addr))),
+ curr->ptr },
+ i32
+ );
+ return curr;
+ }
+};
+
+Pass *createInstrumentMemoryPass() {
+ return new InstrumentMemory();
+}
+
+} // namespace wasm
diff --git a/src/passes/pass.cpp b/src/passes/pass.cpp
index 8da42f9cd..51e76cdf7 100644
--- a/src/passes/pass.cpp
+++ b/src/passes/pass.cpp
@@ -74,6 +74,7 @@ void PassRegistry::registerPasses() {
registerPass("legalize-js-interface", "legalizes i64 types on the import/export boundary", createLegalizeJSInterfacePass);
registerPass("local-cse", "common subexpression elimination inside basic blocks", createLocalCSEPass);
registerPass("log-execution", "instrument the build with logging of where execution goes", createLogExecutionPass);
+ registerPass("instrument-memory", "instrument the build with code to intercept all loads and stores", createInstrumentMemoryPass);
registerPass("memory-packing", "packs memory into separate segments, skipping zeros", createMemoryPackingPass);
registerPass("merge-blocks", "merges blocks to their parents", createMergeBlocksPass);
registerPass("metrics", "reports metrics", createMetricsPass);
diff --git a/src/passes/passes.h b/src/passes/passes.h
index f8156d4fe..709a903f1 100644
--- a/src/passes/passes.h
+++ b/src/passes/passes.h
@@ -33,6 +33,7 @@ Pass *createInliningPass();
Pass *createLegalizeJSInterfacePass();
Pass *createLocalCSEPass();
Pass *createLogExecutionPass();
+Pass *createInstrumentMemoryPass();
Pass *createMemoryPackingPass();
Pass *createMergeBlocksPass();
Pass *createMinifiedPrinterPass();