summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/asmjs/asm_v_wasm.cpp4
-rw-r--r--src/emscripten-optimizer/optimizer-shared.cpp10
-rw-r--r--src/emscripten-optimizer/optimizer.h2
-rw-r--r--src/wasm2js.h30
-rw-r--r--test/wasm2js/refs.2asm.js44
-rw-r--r--test/wasm2js/refs.2asm.js.opt42
-rw-r--r--test/wasm2js/refs.wast33
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)
+ )
+ )
+)