diff options
-rwxr-xr-x | auto_update_tests.py | 11 | ||||
-rwxr-xr-x | check.py | 16 | ||||
-rw-r--r-- | src/binaryen-c.cpp | 23 | ||||
-rw-r--r-- | src/passes/PrintCallGraph.cpp | 24 | ||||
-rw-r--r-- | src/wasm-binary.h | 4 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 77 | ||||
-rw-r--r-- | test/example/c-api-unused-mem.cpp | 93 | ||||
-rw-r--r-- | test/example/c-api-unused-mem.txt | 101 | ||||
-rw-r--r-- | test/stacky.wasm | bin | 0 -> 54 bytes | |||
-rw-r--r-- | test/stacky.wasm.fromBinary | 21 |
10 files changed, 320 insertions, 50 deletions
diff --git a/auto_update_tests.py b/auto_update_tests.py index f65a8c026..294bad750 100755 --- a/auto_update_tests.py +++ b/auto_update_tests.py @@ -177,4 +177,15 @@ for t in os.listdir('test'): actual = actual.replace('printing before:\n', '') open(t, 'w').write(actual) +print '\n[ checking wasm-dis on provided binaries... ]\n' + +for t in os.listdir('test'): + if t.endswith('.wasm') and not t.startswith('spec'): + print '..', t + t = os.path.join('test', t) + cmd = [os.path.join('bin', 'wasm-dis'), t] + actual = run_command(cmd) + + open(t + '.fromBinary', 'w').write(actual) + print '\n[ success! ]' @@ -23,7 +23,7 @@ import sys from scripts.test.support import run_command, split_wast from scripts.test.shared import ( ASM2WASM, BIN_DIR, EMCC, MOZJS, NATIVECC, NATIVEXX, NODEJS, S2WASM_EXE, - WASM_AS, WASM_OPT, WASM_SHELL, WASM_SHELL_EXE, + WASM_AS, WASM_OPT, WASM_SHELL, WASM_SHELL_EXE, WASM_DIS, binary_format_check, delete_from_orbit, fail, fail_with_error, fail_if_not_identical, fail_if_not_contained, has_vanilla_emcc, has_vanilla_llvm, minify_check, num_failures, options, tests, @@ -175,6 +175,20 @@ for t in tests: minify_check(t) +print '\n[ checking wasm-dis on provided binaries... ]\n' + +for t in tests: + if t.endswith('.wasm') and not t.startswith('spec'): + print '..', t + t = os.path.join(options.binaryen_test, t) + cmd = WASM_DIS + [t] + actual = run_command(cmd) + + with open(t + '.fromBinary') as f: + expected = f.read() + if actual != expected: + fail(actual, expected) + print '\n[ checking wasm-shell spec testcases... ]\n' if len(requested) == 0: diff --git a/src/binaryen-c.cpp b/src/binaryen-c.cpp index b8933147f..c618f9d14 100644 --- a/src/binaryen-c.cpp +++ b/src/binaryen-c.cpp @@ -808,6 +808,7 @@ void BinaryenSetMemory(BinaryenModuleRef module, BinaryenIndex initial, Binaryen auto* wasm = (Module*)module; wasm->memory.initial = initial; wasm->memory.max = maximum; + wasm->memory.exists = true; if (exportName) { auto memoryExport = make_unique<Export>(); memoryExport->name = exportName; @@ -1012,17 +1013,17 @@ void BinaryenSetAPITracing(int on) { tracing = on; if (tracing) { - std::cout << "// beginning a Binaryen API trace\n"; - std::cout << "#include <math.h>\n"; - std::cout << "#include <map>\n"; - std::cout << "#include \"src/binaryen-c.h\"\n"; - std::cout << "int main() {\n"; - std::cout << " std::map<size_t, BinaryenFunctionTypeRef> functionTypes;\n"; - std::cout << " std::map<size_t, BinaryenExpressionRef> expressions;\n"; - std::cout << " std::map<size_t, BinaryenFunctionRef> functions;\n"; - std::cout << " std::map<size_t, RelooperBlockRef> relooperBlocks;\n"; - std::cout << " BinaryenModuleRef the_module = NULL;\n"; - std::cout << " RelooperRef the_relooper = NULL;\n"; + std::cout << "// beginning a Binaryen API trace\n" + "#include <math.h>\n" + "#include <map>\n" + "#include \"src/binaryen-c.h\"\n" + "int main() {\n" + " std::map<size_t, BinaryenFunctionTypeRef> functionTypes;\n" + " std::map<size_t, BinaryenExpressionRef> expressions;\n" + " std::map<size_t, BinaryenFunctionRef> functions;\n" + " std::map<size_t, RelooperBlockRef> relooperBlocks;\n" + " BinaryenModuleRef the_module = NULL;\n" + " RelooperRef the_relooper = NULL;\n"; } else { std::cout << " return 0;\n"; std::cout << "}\n"; diff --git a/src/passes/PrintCallGraph.cpp b/src/passes/PrintCallGraph.cpp index 233ae3a0c..d1bfbf04a 100644 --- a/src/passes/PrintCallGraph.cpp +++ b/src/passes/PrintCallGraph.cpp @@ -30,18 +30,18 @@ namespace wasm { struct PrintCallGraph : public Pass { void run(PassRunner* runner, Module* module) override { std::ostream &o = std::cout; - o << "digraph call {\n"; - o << " rankdir = LR;\n"; - o << " subgraph cluster_key {\n"; - o << " node [shape=box, fontname=courier, fontsize=10];\n"; - o << " edge [fontname=courier, fontsize=10];\n"; - o << " label = \"Key\";\n"; - o << " \"Import\" [style=\"filled\", fillcolor=\"turquoise\"];\n"; - o << " \"Export\" [style=\"filled\", fillcolor=\"gray\"];\n"; - o << " \"Indirect Target\" [style=\"filled, rounded\", fillcolor=\"white\"];\n"; - o << " \"A\" -> \"B\" [style=\"filled, rounded\", label = \"Direct Call\"];\n"; - o << " }\n\n"; - o << " node [shape=box, fontname=courier, fontsize=10];\n"; + o << "digraph call {\n" + " rankdir = LR;\n" + " subgraph cluster_key {\n" + " node [shape=box, fontname=courier, fontsize=10];\n" + " edge [fontname=courier, fontsize=10];\n" + " label = \"Key\";\n" + " \"Import\" [style=\"filled\", fillcolor=\"turquoise\"];\n" + " \"Export\" [style=\"filled\", fillcolor=\"gray\"];\n" + " \"Indirect Target\" [style=\"filled, rounded\", fillcolor=\"white\"];\n" + " \"A\" -> \"B\" [style=\"filled, rounded\", label = \"Direct Call\"];\n" + " }\n\n" + " node [shape=box, fontname=courier, fontsize=10];\n"; // All Functions for (auto& func : module->functions) { diff --git a/src/wasm-binary.h b/src/wasm-binary.h index 1edd3fa12..e681f30e8 100644 --- a/src/wasm-binary.h +++ b/src/wasm-binary.h @@ -690,6 +690,7 @@ public: void readFunctions(); std::map<Export*, Index> exportIndexes; + std::vector<Export*> exportOrder; void readExports(); Expression* readExpression(); @@ -704,6 +705,7 @@ public: void processExpressions(); Expression* popExpression(); + Expression* popNonVoidExpression(); std::map<Index, Name> mappedGlobals; // index of the Global => name. first imported globals, then internal globals @@ -736,7 +738,7 @@ public: auto num = type->params.size(); call->operands.resize(num); for (size_t i = 0; i < num; i++) { - call->operands[num - i - 1] = popExpression(); + call->operands[num - i - 1] = popNonVoidExpression(); } call->type = type->result; } diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index ebbc5a8ee..e6b33dbb0 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -1271,6 +1271,7 @@ void WasmBinaryBuilder::readExports() { curr->kind = (ExternalKind)getU32LEB(); auto index = getU32LEB(); exportIndexes[curr] = index; + exportOrder.push_back(curr); } } @@ -1319,6 +1320,32 @@ Expression* WasmBinaryBuilder::popExpression() { return ret; } +Expression* WasmBinaryBuilder::popNonVoidExpression() { + auto* ret = popExpression(); + if (ret->type != none) return ret; + // we found a void, so this is stacky code that we must handle carefully + Builder builder(wasm); + // add elements until we find a non-void + std::vector<Expression*> expressions; + expressions.push_back(ret); + while (1) { + auto* curr = popExpression(); + expressions.push_back(curr); + if (curr->type != none) break; + } + auto* block = builder.makeBlock(); + while (!expressions.empty()) { + block->list.push_back(expressions.back()); + expressions.pop_back(); + } + auto type = block->list[0]->type; + auto local = builder.addVar(currFunction, type); + block->list[0] = builder.makeSetLocal(local, block->list[0]); + block->list.push_back(builder.makeGetLocal(local, type)); + block->finalize(); + return block; +} + Name WasmBinaryBuilder::getGlobalName(Index index) { if (!mappedGlobals.size()) { // Create name => index mapping. @@ -1346,16 +1373,16 @@ void WasmBinaryBuilder::processFunctions() { wasm.start = getFunctionIndexName(startIndex); } - for (auto& iter : exportIndexes) { - Export* curr = iter.first; + for (auto* curr : exportOrder) { + auto index = exportIndexes[curr]; switch (curr->kind) { case ExternalKind::Function: { - curr->value = getFunctionIndexName(iter.second); + curr->value = getFunctionIndexName(index); break; } case ExternalKind::Table: curr->value = Name::fromInt(0); break; case ExternalKind::Memory: curr->value = Name::fromInt(0); break; - case ExternalKind::Global: curr->value = getGlobalName(iter.second); break; + case ExternalKind::Global: curr->value = getGlobalName(index); break; default: WASM_UNREACHABLE(); } wasm.addExport(curr); @@ -1562,7 +1589,7 @@ Expression* WasmBinaryBuilder::getBlock(WasmType type) { void WasmBinaryBuilder::visitIf(If *curr) { if (debug) std::cerr << "zz node: If" << std::endl; curr->type = getWasmType(); - curr->condition = popExpression(); + curr->condition = popNonVoidExpression(); curr->ifTrue = getBlock(curr->type); if (lastSeparator == BinaryConsts::Else) { curr->ifFalse = getBlock(curr->type); @@ -1592,14 +1619,14 @@ void WasmBinaryBuilder::visitBreak(Break *curr, uint8_t code) { if (debug) std::cerr << "zz node: Break, code "<< int32_t(code) << std::endl; BreakTarget target = getBreakTarget(getU32LEB()); curr->name = target.name; - if (code == BinaryConsts::BrIf) curr->condition = popExpression(); - if (target.arity) curr->value = popExpression(); + if (code == BinaryConsts::BrIf) curr->condition = popNonVoidExpression(); + if (target.arity) curr->value = popNonVoidExpression(); curr->finalize(); } void WasmBinaryBuilder::visitSwitch(Switch *curr) { if (debug) std::cerr << "zz node: Switch" << std::endl; - curr->condition = popExpression(); + curr->condition = popNonVoidExpression(); auto numTargets = getU32LEB(); if (debug) std::cerr << "targets: "<< numTargets<<std::endl; @@ -1609,7 +1636,7 @@ void WasmBinaryBuilder::visitSwitch(Switch *curr) { auto defaultTarget = getBreakTarget(getU32LEB()); curr->default_ = defaultTarget.name; if (debug) std::cerr << "default: "<< curr->default_<<std::endl; - if (defaultTarget.arity) curr->value = popExpression(); + if (defaultTarget.arity) curr->value = popNonVoidExpression(); } Expression* WasmBinaryBuilder::visitCall() { @@ -1646,9 +1673,9 @@ void WasmBinaryBuilder::visitCallIndirect(CallIndirect *curr) { curr->fullType = fullType->name; auto num = fullType->params.size(); curr->operands.resize(num); - curr->target = popExpression(); + curr->target = popNonVoidExpression(); for (size_t i = 0; i < num; i++) { - curr->operands[num - i - 1] = popExpression(); + curr->operands[num - i - 1] = popNonVoidExpression(); } curr->type = fullType->result; } @@ -1664,7 +1691,7 @@ void WasmBinaryBuilder::visitSetLocal(SetLocal *curr, uint8_t code) { if (debug) std::cerr << "zz node: Set|TeeLocal" << std::endl; curr->index = getU32LEB(); assert(curr->index < currFunction->getNumLocals()); - curr->value = popExpression(); + curr->value = popNonVoidExpression(); curr->type = curr->value->type; curr->setTee(code == BinaryConsts::TeeLocal); } @@ -1690,7 +1717,7 @@ void WasmBinaryBuilder::visitSetGlobal(SetGlobal *curr) { if (debug) std::cerr << "zz node: SetGlobal" << std::endl; auto index = getU32LEB(); curr->name = getGlobalName(index); - curr->value = popExpression(); + curr->value = popNonVoidExpression(); } void WasmBinaryBuilder::readMemoryAccess(Address& alignment, size_t bytes, Address& offset) { @@ -1719,7 +1746,7 @@ bool WasmBinaryBuilder::maybeVisitLoad(Expression*& out, uint8_t code) { } if (debug) std::cerr << "zz node: Load" << std::endl; readMemoryAccess(curr->align, curr->bytes, curr->offset); - curr->ptr = popExpression(); + curr->ptr = popNonVoidExpression(); out = curr; return true; } @@ -1740,8 +1767,8 @@ bool WasmBinaryBuilder::maybeVisitStore(Expression*& out, uint8_t code) { } if (debug) std::cerr << "zz node: Store" << std::endl; readMemoryAccess(curr->align, curr->bytes, curr->offset); - curr->value = popExpression(); - curr->ptr = popExpression(); + curr->value = popNonVoidExpression(); + curr->ptr = popNonVoidExpression(); curr->finalize(); out = curr; return true; @@ -1821,7 +1848,7 @@ bool WasmBinaryBuilder::maybeVisitUnary(Expression*& out, uint8_t code) { default: return false; } if (debug) std::cerr << "zz node: Unary" << std::endl; - curr->value = popExpression(); + curr->value = popNonVoidExpression(); out = curr; return true; } @@ -1878,8 +1905,8 @@ bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) { default: return false; } if (debug) std::cerr << "zz node: Binary" << std::endl; - curr->right = popExpression(); - curr->left = popExpression(); + curr->right = popNonVoidExpression(); + curr->left = popNonVoidExpression(); curr->finalize(); out = curr; return true; @@ -1890,16 +1917,16 @@ bool WasmBinaryBuilder::maybeVisitBinary(Expression*& out, uint8_t code) { void WasmBinaryBuilder::visitSelect(Select *curr) { if (debug) std::cerr << "zz node: Select" << std::endl; - curr->condition = popExpression(); - curr->ifFalse = popExpression(); - curr->ifTrue = popExpression(); + curr->condition = popNonVoidExpression(); + curr->ifFalse = popNonVoidExpression(); + curr->ifTrue = popNonVoidExpression(); curr->finalize(); } void WasmBinaryBuilder::visitReturn(Return *curr) { if (debug) std::cerr << "zz node: Return" << std::endl; if (currFunction->result != none) { - curr->value = popExpression(); + curr->value = popNonVoidExpression(); } } @@ -1916,7 +1943,7 @@ bool WasmBinaryBuilder::maybeVisitHost(Expression*& out, uint8_t code) { curr = allocator.alloc<Host>(); curr->op = GrowMemory; curr->operands.resize(1); - curr->operands[0] = popExpression(); + curr->operands[0] = popNonVoidExpression(); break; } default: return false; @@ -1939,7 +1966,7 @@ void WasmBinaryBuilder::visitUnreachable(Unreachable *curr) { void WasmBinaryBuilder::visitDrop(Drop *curr) { if (debug) std::cerr << "zz node: Drop" << std::endl; - curr->value = popExpression(); + curr->value = popNonVoidExpression(); } } // namespace wasm diff --git a/test/example/c-api-unused-mem.cpp b/test/example/c-api-unused-mem.cpp new file mode 100644 index 000000000..69bee351f --- /dev/null +++ b/test/example/c-api-unused-mem.cpp @@ -0,0 +1,93 @@ +// beginning a Binaryen API trace +#include <stdio.h> +#include <math.h> +#include <map> +#include "binaryen-c.h" +int main() { + std::map<size_t, BinaryenFunctionTypeRef> functionTypes; + std::map<size_t, BinaryenExpressionRef> expressions; + std::map<size_t, BinaryenFunctionRef> functions; + std::map<size_t, RelooperBlockRef> relooperBlocks; + BinaryenModuleRef the_module = NULL; + RelooperRef the_relooper = NULL; + the_module = BinaryenModuleCreate(); + expressions[size_t(NULL)] = BinaryenExpressionRef(NULL); + BinaryenModuleAutoDrop(the_module); + { + const char* segments[] = { 0 }; + BinaryenExpressionRef segmentOffsets[] = { 0 }; + BinaryenIndex segmentSizes[] = { 0 }; + BinaryenSetMemory(the_module, 256, 256, "memory", segments, segmentOffsets, segmentSizes, 0); + } + the_relooper = RelooperCreate(); + { + BinaryenExpressionRef children[] = { 0 }; + expressions[1] = BinaryenBlock(the_module, "bb0", children, 0); + } + relooperBlocks[0] = RelooperAddBlock(the_relooper, expressions[1]); + expressions[2] = BinaryenGetLocal(the_module, 0, 1); + expressions[3] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + expressions[4] = BinaryenStore(the_module, 4, 0, 0, expressions[3], expressions[2], 1); + expressions[5] = BinaryenReturn(the_module, expressions[0]); + { + BinaryenExpressionRef children[] = { expressions[4], expressions[5] }; + expressions[6] = BinaryenBlock(the_module, "bb1", children, 2); + } + relooperBlocks[1] = RelooperAddBlock(the_relooper, expressions[6]); + RelooperAddBranch(relooperBlocks[0], relooperBlocks[1], expressions[0], expressions[0]); + { + BinaryenIndex paramTypes[] = { 0 }; + functionTypes[0] = BinaryenAddFunctionType(the_module, "rustfn-0-3", 0, paramTypes, 0); + } + expressions[7] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + expressions[8] = BinaryenLoad(the_module, 4, 0, 0, 0, 1, expressions[7]); + expressions[9] = BinaryenSetLocal(the_module, 0, expressions[8]); + relooperBlocks[2] = RelooperAddBlock(the_relooper, expressions[9]); + RelooperAddBranch(relooperBlocks[2], relooperBlocks[0], expressions[0], expressions[0]); + expressions[10] = RelooperRenderAndDispose(the_relooper, relooperBlocks[2], 1, the_module); + { + BinaryenType varTypes[] = { 1, 1, 2 }; + functions[0] = BinaryenAddFunction(the_module, "main", functionTypes[0], varTypes, 3, expressions[10]); + } + BinaryenAddExport(the_module, "main", "main"); + { + BinaryenIndex paramTypes[] = { 0 }; + functionTypes[1] = BinaryenAddFunctionType(the_module, "__wasm_start", 0, paramTypes, 0); + } + { + const char* segments[] = { 0 }; + BinaryenExpressionRef segmentOffsets[] = { 0 }; + BinaryenIndex segmentSizes[] = { 0 }; + BinaryenSetMemory(the_module, 1024, 1024, NULL, segments, segmentOffsets, segmentSizes, 0); + } + expressions[11] = BinaryenConst(the_module, BinaryenLiteralInt32(65535)); + expressions[12] = BinaryenConst(the_module, BinaryenLiteralInt32(0)); + expressions[13] = BinaryenStore(the_module, 4, 0, 0, expressions[12], expressions[11], 1); + { + BinaryenExpressionRef operands[] = { 0 }; + expressions[14] = BinaryenCall(the_module, "main", operands, 0, 0); + } + { + BinaryenExpressionRef children[] = { expressions[13], expressions[14] }; + expressions[15] = BinaryenBlock(the_module, NULL, children, 2); + } + BinaryenAddExport(the_module, "__wasm_start", "rust_entry"); + { + BinaryenType varTypes[] = { 0 }; + functions[1] = BinaryenAddFunction(the_module, "__wasm_start", functionTypes[1], varTypes, 0, expressions[15]); + } + BinaryenModuleValidate(the_module); + BinaryenModulePrint(the_module); + // check that binary read-write works + { + char buffer[1024]; + size_t size = BinaryenModuleWrite(the_module, buffer, 1024); + printf("%d\n", size); + BinaryenModuleRef copy = BinaryenModuleRead(buffer, size); + BinaryenModulePrint(copy); + BinaryenModuleDispose(copy); + } + BinaryenModuleDispose(the_module); + return 0; +} + diff --git a/test/example/c-api-unused-mem.txt b/test/example/c-api-unused-mem.txt new file mode 100644 index 000000000..cae196ea7 --- /dev/null +++ b/test/example/c-api-unused-mem.txt @@ -0,0 +1,101 @@ +(module + (type $rustfn-0-3 (func)) + (type $__wasm_start (func)) + (memory $0 1024 1024) + (export "memory" (memory $0)) + (export "main" (func $main)) + (export "rust_entry" (func $__wasm_start)) + (func $main (type $rustfn-0-3) + (local $0 i32) + (local $1 i32) + (local $2 i64) + (block $block$1$break + (set_local $0 + (i32.load + (i32.const 0) + ) + ) + (block + (br $block$1$break) + ) + ) + (block + (block $block$2$break + (block $bb0 + ) + (block + (br $block$2$break) + ) + ) + (block + (block $bb1 + (i32.store + (i32.const 0) + (get_local $0) + ) + (return) + ) + ) + ) + ) + (func $__wasm_start (type $__wasm_start) + (i32.store + (i32.const 0) + (i32.const 65535) + ) + (call $main) + ) +) +195 +(module + (type $0 (func)) + (type $1 (func)) + (memory $0 1024 1024) + (export "memory" (memory $0)) + (export "main" (func $main)) + (export "rust_entry" (func $__wasm_start)) + (func $main (type $0) + (local $var$0 i32) + (local $var$1 i32) + (local $var$2 i64) + (block $label$0 + (block $label$1 + (set_local $var$0 + (i32.load + (i32.const 0) + ) + ) + (block $label$2 + (br $label$1) + ) + ) + (block $label$3 + (block $label$4 + (block $label$5 + ) + (block $label$6 + (br $label$4) + ) + ) + (block $label$7 + (block $label$8 + (i32.store + (i32.const 0) + (get_local $var$0) + ) + (return) + ) + ) + ) + ) + ) + (func $__wasm_start (type $1) + (block $label$0 + (i32.store + (i32.const 0) + (i32.const 65535) + ) + (call $main) + ) + ) +) diff --git a/test/stacky.wasm b/test/stacky.wasm Binary files differnew file mode 100644 index 000000000..27b86992a --- /dev/null +++ b/test/stacky.wasm diff --git a/test/stacky.wasm.fromBinary b/test/stacky.wasm.fromBinary new file mode 100644 index 000000000..13250bd39 --- /dev/null +++ b/test/stacky.wasm.fromBinary @@ -0,0 +1,21 @@ +(module + (type $0 (func (param i32 i32) (result i32))) + (memory $0 256 256) + (export "add" (func $0)) + (func $0 (type $0) (param $var$0 i32) (param $var$1 i32) (result i32) + (local $2 i32) + (i32.add + (block i32 + (set_local $2 + (get_local $var$0) + ) + (set_local $var$0 + (i32.const 100) + ) + (get_local $2) + ) + (get_local $var$1) + ) + ) +) + |