summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/tools/wasm2js.cpp50
-rw-r--r--test/wasm2js.asserts.js4
-rw-r--r--test/wasm2js.traps.js12
3 files changed, 39 insertions, 27 deletions
diff --git a/src/tools/wasm2js.cpp b/src/tools/wasm2js.cpp
index 8659ef6e2..06b24ea26 100644
--- a/src/tools/wasm2js.cpp
+++ b/src/tools/wasm2js.cpp
@@ -557,7 +557,9 @@ private:
ToolOptions options;
Module tempAllocationModule;
+ Expression* parseInvoke(Builder& wasmBuilder, Module& module, Element& e);
Ref emitAssertReturnFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule);
@@ -566,10 +568,12 @@ private:
Name testFuncName,
Name asmModule);
Ref emitAssertTrapFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule);
Ref emitInvokeFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule);
@@ -589,11 +593,27 @@ private:
}
};
+Expression* AssertionEmitter::parseInvoke(Builder& wasmBuilder,
+ Module& module,
+ Element& e) {
+ // After legalization, the sexpBuilder doesn't necessarily have correct type
+ // information about all of the functions in the module, so create the call
+ // manually and only use the parser for the operands.
+ Name target = e[1]->str();
+ std::vector<Expression*> args;
+ for (size_t i = 2; i < e.size(); ++i) {
+ args.push_back(sexpBuilder.parseExpression(e[i]));
+ }
+ Type type = module.getFunction(module.getExport(target)->value)->sig.results;
+ return wasmBuilder.makeCall(target, args, type);
+}
+
Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule) {
- Expression* actual = sexpBuilder.parseExpression(e[1]);
+ Expression* actual = parseInvoke(wasmBuilder, module, *e[1]);
Expression* body = nullptr;
if (e.size() == 2) {
if (actual->type == Type::none) {
@@ -604,7 +624,6 @@ Ref AssertionEmitter::emitAssertReturnFunc(Builder& wasmBuilder,
} else if (e.size() == 3) {
Expression* expected = sexpBuilder.parseExpression(e[2]);
Type resType = expected->type;
- actual->type = resType;
TODO_SINGLE_COMPOUND(resType);
switch (resType.getBasic()) {
case Type::i32:
@@ -667,11 +686,12 @@ Ref AssertionEmitter::emitAssertReturnNanFunc(Builder& wasmBuilder,
}
Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule) {
Name innerFuncName("f");
- Expression* expr = sexpBuilder.parseExpression(e[1]);
+ Expression* expr = parseInvoke(wasmBuilder, module, *e[1]);
std::unique_ptr<Function> exprFunc(
wasmBuilder.makeFunction(innerFuncName,
std::vector<NameType>{},
@@ -701,10 +721,11 @@ Ref AssertionEmitter::emitAssertTrapFunc(Builder& wasmBuilder,
}
Ref AssertionEmitter::emitInvokeFunc(Builder& wasmBuilder,
+ Module& module,
Element& e,
Name testFuncName,
Name asmModule) {
- Expression* body = sexpBuilder.parseExpression(e);
+ Expression* body = parseInvoke(wasmBuilder, module, e);
std::unique_ptr<Function> testFunc(
wasmBuilder.makeFunction(testFuncName,
std::vector<NameType>{},
@@ -812,17 +833,19 @@ void AssertionEmitter::emit() {
Builder wasmBuilder(sexpBuilder.getModule());
Name asmModule = std::string("ret") + ASM_FUNC.str;
+ // Track the last built module.
+ Module wasm;
for (size_t i = 0; i < root.size(); ++i) {
Element& e = *root[i];
if (e.isList() && e.size() >= 1 && e[0]->isStr() &&
e[0]->str() == Name("module")) {
+ ModuleUtils::clearModule(wasm);
std::stringstream funcNameS;
funcNameS << ASM_FUNC.c_str() << i;
std::stringstream moduleNameS;
moduleNameS << "ret" << ASM_FUNC.c_str() << i;
Name funcName(funcNameS.str().c_str());
asmModule = Name(moduleNameS.str().c_str());
- Module wasm;
options.applyFeatures(wasm);
SExpressionWasmBuilder builder(wasm, e, options.profile);
emitWasm(wasm, out, flags, options.passOptions, funcName);
@@ -836,29 +859,18 @@ void AssertionEmitter::emit() {
bool isInvoke = (e[0]->str() == Name("invoke"));
bool isReturn = (e[0]->str() == Name("assert_return"));
bool isReturnNan = (e[0]->str() == Name("assert_return_nan"));
- Element* assertOp;
- // An assertion of an invoke has the invoke inside the assert.
- if (isAssertHandled(e)) {
- assertOp = e[1];
- } else {
- assertOp = &e;
- }
- // Replace "invoke" with "call"
- (*assertOp)[0]->setString(IString("call"), false, false);
- // Need to claim dollared to get string as function target
- (*assertOp)[1]->setString((*assertOp)[1]->str(), /*dollared=*/true, false);
if (isInvoke) {
- emitInvokeFunc(wasmBuilder, e, testFuncName, asmModule);
+ emitInvokeFunc(wasmBuilder, wasm, e, testFuncName, asmModule);
out << testFuncName.str << "();\n";
continue;
}
// Otherwise, this is some form of assertion.
if (isReturn) {
- emitAssertReturnFunc(wasmBuilder, e, testFuncName, asmModule);
+ emitAssertReturnFunc(wasmBuilder, wasm, e, testFuncName, asmModule);
} else if (isReturnNan) {
emitAssertReturnNanFunc(wasmBuilder, e, testFuncName, asmModule);
} else {
- emitAssertTrapFunc(wasmBuilder, e, testFuncName, asmModule);
+ emitAssertTrapFunc(wasmBuilder, wasm, e, testFuncName, asmModule);
}
out << "if (!" << testFuncName.str << "()) throw 'assertion failed: " << e
diff --git a/test/wasm2js.asserts.js b/test/wasm2js.asserts.js
index 6ff356893..2770c07dd 100644
--- a/test/wasm2js.asserts.js
+++ b/test/wasm2js.asserts.js
@@ -74,9 +74,9 @@ function check1() {
return 1 | 0;
}
-if (!check1()) throw 'assertion failed: ( assert_return ( call $empty ) )';
+if (!check1()) throw 'assertion failed: ( assert_return ( invoke empty ) )';
function check2() {
return (retasmFunc0.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
}
-if (!check2()) throw 'assertion failed: ( assert_return ( call $add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
+if (!check2()) throw 'assertion failed: ( assert_return ( invoke add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
diff --git a/test/wasm2js.traps.js b/test/wasm2js.traps.js
index f5bb8477f..d3b672dd1 100644
--- a/test/wasm2js.traps.js
+++ b/test/wasm2js.traps.js
@@ -74,15 +74,15 @@ function check1() {
return 1 | 0;
}
-if (!check1()) throw 'assertion failed: ( assert_return ( call $empty ) )';
+if (!check1()) throw 'assertion failed: ( assert_return ( invoke empty ) )';
function check2() {
return (retasmFunc0.add(1 | 0, 1 | 0) | 0 | 0) == (2 | 0) | 0;
}
-if (!check2()) throw 'assertion failed: ( assert_return ( call $add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
+if (!check2()) throw 'assertion failed: ( assert_return ( invoke add ( i32.const 1 ) ( i32.const 1 ) ) ( i32.const 2 ) )';
function check3() {
function f() {
- retasmFunc0.div_s(0 | 0, 0 | 0);
+ return retasmFunc0.div_s(0 | 0, 0 | 0) | 0 | 0;
}
try {
@@ -93,10 +93,10 @@ function check3() {
return 0;
}
-if (!check3()) throw 'assertion failed: ( assert_trap ( call $div_s ( i32.const 0 ) ( i32.const 0 ) ) integer divide by zero )';
+if (!check3()) throw 'assertion failed: ( assert_trap ( invoke div_s ( i32.const 0 ) ( i32.const 0 ) ) integer divide by zero )';
function check4() {
function f() {
- retasmFunc0.div_s(-2147483648 | 0, -1 | 0);
+ return retasmFunc0.div_s(-2147483648 | 0, -1 | 0) | 0 | 0;
}
try {
@@ -107,4 +107,4 @@ function check4() {
return 0;
}
-if (!check4()) throw 'assertion failed: ( assert_trap ( call $div_s ( i32.const 0x80000000 ) ( i32.const -1 ) ) integer overflow )';
+if (!check4()) throw 'assertion failed: ( assert_trap ( invoke div_s ( i32.const 0x80000000 ) ( i32.const -1 ) ) integer overflow )';