diff options
-rw-r--r-- | src/asmjs/asm_v_wasm.cpp | 4 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer-shared.cpp | 10 | ||||
-rw-r--r-- | src/emscripten-optimizer/optimizer.h | 2 | ||||
-rw-r--r-- | src/wasm2js.h | 30 | ||||
-rw-r--r-- | test/wasm2js/refs.2asm.js | 44 | ||||
-rw-r--r-- | test/wasm2js/refs.2asm.js.opt | 42 | ||||
-rw-r--r-- | test/wasm2js/refs.wast | 33 |
7 files changed, 148 insertions, 17 deletions
diff --git a/src/asmjs/asm_v_wasm.cpp b/src/asmjs/asm_v_wasm.cpp index 314c2494f..bbbaad5bc 100644 --- a/src/asmjs/asm_v_wasm.cpp +++ b/src/asmjs/asm_v_wasm.cpp @@ -21,6 +21,10 @@ namespace wasm { JsType wasmToJsType(Type type) { + if (type.isRef()) { + return JS_REF; + } + TODO_SINGLE_COMPOUND(type); switch (type.getBasic()) { case Type::i32: diff --git a/src/emscripten-optimizer/optimizer-shared.cpp b/src/emscripten-optimizer/optimizer-shared.cpp index 8208f6f47..773c5d9fc 100644 --- a/src/emscripten-optimizer/optimizer-shared.cpp +++ b/src/emscripten-optimizer/optimizer-shared.cpp @@ -104,6 +104,11 @@ Ref makeJsCoercedZero(JsType type) { abort(); } +bool needsJsCoercion(JsType type) { + // References need no coercion, but everything else does. + return type != JS_REF; +} + Ref makeJsCoercion(Ref node, JsType type) { switch (type) { case JS_INT: @@ -122,10 +127,11 @@ Ref makeJsCoercion(Ref node, JsType type) { return ValueBuilder::makeCall(SIMD_INT16X8_CHECK, node); case JS_INT32X4: return ValueBuilder::makeCall(SIMD_INT32X4_CHECK, node); + case JS_REF: case JS_NONE: default: - // non-validating code, emit nothing XXX this is dangerous, we should only - // allow this when we know we are not validating + // No coercion is needed. + // TODO see if JS_NONE is actually used here. return node; } } diff --git a/src/emscripten-optimizer/optimizer.h b/src/emscripten-optimizer/optimizer.h index a27fe25eb..6347c194c 100644 --- a/src/emscripten-optimizer/optimizer.h +++ b/src/emscripten-optimizer/optimizer.h @@ -39,6 +39,7 @@ enum JsType { JS_INT16X8, JS_INT32X4, JS_INT64, + JS_REF, JS_NONE // number of types }; @@ -51,6 +52,7 @@ enum JsSign { }; cashew::Ref makeJsCoercedZero(JsType type); +bool needsJsCoercion(JsType type); cashew::Ref makeJsCoercion(cashew::Ref node, JsType type); cashew::Ref makeSigning(cashew::Ref node, JsSign sign); diff --git a/src/wasm2js.h b/src/wasm2js.h index 7540bd71a..2084c0453 100644 --- a/src/wasm2js.h +++ b/src/wasm2js.h @@ -921,11 +921,13 @@ Ref Wasm2JSBuilder::processFunction(Module* m, IString name = fromName(func->getLocalNameOrGeneric(i), NameScope::Local); ValueBuilder::appendArgumentToFunction(ret, name); if (needCoercions) { - ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary( - ValueBuilder::makeName(name), - SET, - makeJsCoercion(ValueBuilder::makeName(name), - wasmToJsType(func->getLocalType(i)))))); + auto jsType = wasmToJsType(func->getLocalType(i)); + if (needsJsCoercion(jsType)) { + ret[3]->push_back(ValueBuilder::makeStatement(ValueBuilder::makeBinary( + ValueBuilder::makeName(name), + SET, + makeJsCoercion(ValueBuilder::makeName(name), jsType)))); + } } } Ref theVar = ValueBuilder::makeVar(); @@ -2219,21 +2221,19 @@ Ref Wasm2JSBuilder::processFunctionBody(Module* m, visit(curr->value, EXPRESSION_RESULT), visit(curr->size, EXPRESSION_RESULT)); } - Ref visitRefNull(RefNull* curr) { - unimplemented(curr); - WASM_UNREACHABLE("unimp"); - } + Ref visitRefNull(RefNull* curr) { return ValueBuilder::makeName("null"); } Ref visitRefIsNull(RefIsNull* curr) { - unimplemented(curr); - WASM_UNREACHABLE("unimp"); + return ValueBuilder::makeBinary(visit(curr->value, EXPRESSION_RESULT), + EQ, + ValueBuilder::makeName("null")); } Ref visitRefFunc(RefFunc* curr) { - unimplemented(curr); - WASM_UNREACHABLE("unimp"); + return ValueBuilder::makeName(fromName(curr->func, NameScope::Top)); } Ref visitRefEq(RefEq* curr) { - unimplemented(curr); - WASM_UNREACHABLE("unimp"); + return ValueBuilder::makeBinary(visit(curr->left, EXPRESSION_RESULT), + EQ, + visit(curr->right, EXPRESSION_RESULT)); } Ref visitTableGet(TableGet* curr) { unimplemented(curr); diff --git a/test/wasm2js/refs.2asm.js b/test/wasm2js/refs.2asm.js new file mode 100644 index 000000000..0133159b9 --- /dev/null +++ b/test/wasm2js/refs.2asm.js @@ -0,0 +1,44 @@ + +function asmFunc(imports) { + var Math_imul = Math.imul; + var Math_fround = Math.fround; + var Math_abs = Math.abs; + var Math_clz32 = Math.clz32; + var Math_min = Math.min; + var Math_max = Math.max; + var Math_floor = Math.floor; + var Math_ceil = Math.ceil; + var Math_trunc = Math.trunc; + var Math_sqrt = Math.sqrt; + function null_() { + return null; + } + + function is_null(ref) { + return ref == null | 0; + } + + function ref_func() { + var ref_func_1 = 0; + ref_func_1 = ref_func_1 + 1 | 0; + return ref_func; + } + + function ref_eq(x, y) { + return x == y | 0; + } + + return { + "null_": null_, + "is_null": is_null, + "ref_func": ref_func, + "ref_eq": ref_eq + }; +} + +var retasmFunc = asmFunc({ +}); +export var null_ = retasmFunc.null_; +export var is_null = retasmFunc.is_null; +export var ref_func = retasmFunc.ref_func; +export var ref_eq = retasmFunc.ref_eq; diff --git a/test/wasm2js/refs.2asm.js.opt b/test/wasm2js/refs.2asm.js.opt new file mode 100644 index 000000000..e38afe1cf --- /dev/null +++ b/test/wasm2js/refs.2asm.js.opt @@ -0,0 +1,42 @@ + +function asmFunc(imports) { + var Math_imul = Math.imul; + var Math_fround = Math.fround; + var Math_abs = Math.abs; + var Math_clz32 = Math.clz32; + var Math_min = Math.min; + var Math_max = Math.max; + var Math_floor = Math.floor; + var Math_ceil = Math.ceil; + var Math_trunc = Math.trunc; + var Math_sqrt = Math.sqrt; + function null_() { + return null; + } + + function is_null($0) { + return $0 == null | 0; + } + + function ref_func() { + return ref_func; + } + + function ref_eq($0, $1) { + return $0 == $1 | 0; + } + + return { + "null_": null_, + "is_null": is_null, + "ref_func": ref_func, + "ref_eq": ref_eq + }; +} + +var retasmFunc = asmFunc({ +}); +export var null_ = retasmFunc.null_; +export var is_null = retasmFunc.is_null; +export var ref_func = retasmFunc.ref_func; +export var ref_eq = retasmFunc.ref_eq; diff --git a/test/wasm2js/refs.wast b/test/wasm2js/refs.wast new file mode 100644 index 000000000..4e133c03e --- /dev/null +++ b/test/wasm2js/refs.wast @@ -0,0 +1,33 @@ +(module + (func $null (export "null") (result anyref) + (ref.null any) + ) + + (func $is_null (export "is_null") (param $ref anyref) (result i32) + (ref.is_null + (local.get $ref) + ) + ) + + (func $ref.func (export "ref.func") (result funcref) + ;; Test that we are aware that "$ref.func" below refers to the function and + ;; not the local. This code will keep the local around (at least in an + ;; unoptimized build), and it should use a different name than the function. + (local $ref.func i32) + (local.set $ref.func + (i32.add + (local.get $ref.func) + (i32.const 1) + ) + ) + + (ref.func $ref.func) + ) + + (func $ref.eq (export "ref.eq") (param $x eqref) (param $y eqref) (result i32) + (ref.eq + (local.get $x) + (local.get $y) + ) + ) +) |