Title: [246504] trunk
Revision
246504
Author
justin_mich...@apple.com
Date
2019-06-17 11:44:18 -0700 (Mon, 17 Jun 2019)

Log Message

[WASM-References] Add support for Funcref in parameters and return types
https://bugs.webkit.org/show_bug.cgi?id=198157

Reviewed by Yusuke Suzuki.

JSTests:

* wasm/Builder.js:
(export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
* wasm/references/anyref_globals.js:
* wasm/references/func_ref.js: Added.
(fullGC.gc.makeExportedFunction):
(makeExportedIdent):
(makeAnyfuncIdent):
(fun):
(assert.eq.instance.exports.fix.fun):
(assert.eq.instance.exports.fix):
(string_appeared_here.End.End.Function.End.Code.End.WebAssembly.imp.ref):
(string_appeared_here.End.End.Function.End.Code.End.WebAssembly):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws):
(GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly):
(assert.throws):
(assert.throws.doTest):
(let.importedFun.of):
(makeAnyfuncIdent.fun):
* wasm/references/validation.js:
(assert.throws):
* wasm/wasm.json:

Source/_javascript_Core:

Add support for funcref in parameters, globals, and in table.get/set. When converting a JSValue to
a funcref (nee anyfunc), we first make sure it is an exported wasm function or null.

We also add support for Ref.func. Anywhere a Ref.func is used, (statically) we construct a JS wrapper
for it so that we never need to construct JSValues when handling references. This should make threads
easier to implement.

Finally, we add some missing bounds checks for table.get/set.

* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::tmpForType):
(JSC::Wasm::AirIRGenerator::moveOpForValueType):
(JSC::Wasm::AirIRGenerator::AirIRGenerator):
(JSC::Wasm::AirIRGenerator::addLocal):
(JSC::Wasm::AirIRGenerator::addConstant):
(JSC::Wasm::AirIRGenerator::addRefFunc):
(JSC::Wasm::AirIRGenerator::addTableSet):
(JSC::Wasm::AirIRGenerator::setGlobal):
(JSC::Wasm::AirIRGenerator::addReturn):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addLocal):
(JSC::Wasm::B3IRGenerator::addTableSet):
(JSC::Wasm::B3IRGenerator::addRefFunc):
(JSC::Wasm::B3IRGenerator::setGlobal):
* wasm/WasmBBQPlan.cpp:
(JSC::Wasm::BBQPlan::compileFunctions):
* wasm/WasmCallingConvention.h:
(JSC::Wasm::CallingConventionAir::marshallArgument const):
(JSC::Wasm::CallingConventionAir::setupCall const):
* wasm/WasmExceptionType.h:
* wasm/WasmFormat.h:
(JSC::Wasm::isValueType):
(JSC::Wasm::isSubtype):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* wasm/WasmInstance.cpp:
(JSC::Wasm::Instance::Instance):
(JSC::Wasm::Instance::getFunctionWrapper const):
(JSC::Wasm::Instance::setFunctionWrapper):
* wasm/WasmInstance.h:
* wasm/WasmModuleInformation.h:
(JSC::Wasm::ModuleInformation::referencedFunctions const):
(JSC::Wasm::ModuleInformation::addReferencedFunction const):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseGlobal):
(JSC::Wasm::SectionParser::parseInitExpr):
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::addTableGet):
(JSC::Wasm::Validate::addTableSet):
(JSC::Wasm::Validate::addRefIsNull):
(JSC::Wasm::Validate::addRefFunc):
(JSC::Wasm::Validate::setLocal):
(JSC::Wasm::Validate::addCall):
(JSC::Wasm::Validate::addCallIndirect):
* wasm/js/JSToWasm.cpp:
(JSC::Wasm::createJSToWasmWrapper):
* wasm/js/JSWebAssemblyHelpers.h:
(JSC::isWebAssemblyHostFunction):
* wasm/js/JSWebAssemblyInstance.cpp:
(JSC::JSWebAssemblyInstance::visitChildren):
* wasm/js/JSWebAssemblyRuntimeError.cpp:
(JSC::createJSWebAssemblyRuntimeError):
* wasm/js/JSWebAssemblyRuntimeError.h:
* wasm/js/WasmToJS.cpp:
(JSC::Wasm::handleBadI64Use):
(JSC::Wasm::wasmToJS):
(JSC::Wasm::emitWasmToJSException):
* wasm/js/WasmToJS.h:
* wasm/js/WebAssemblyFunction.cpp:
(JSC::callWebAssemblyFunction):
(JSC::WebAssemblyFunction::jsCallEntrypointSlow):
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
* wasm/wasm.json:

Modified Paths

Added Paths

Diff

Modified: trunk/JSTests/ChangeLog (246503 => 246504)


--- trunk/JSTests/ChangeLog	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/JSTests/ChangeLog	2019-06-17 18:44:18 UTC (rev 246504)
@@ -1,3 +1,33 @@
+2019-06-17  Justin Michaud  <justin_mich...@apple.com>
+
+        [WASM-References] Add support for Funcref in parameters and return types
+        https://bugs.webkit.org/show_bug.cgi?id=198157
+
+        Reviewed by Yusuke Suzuki.
+
+        * wasm/Builder.js:
+        (export.default.Builder.prototype._registerSectionBuilders.const.section.in.WASM.description.section.switch.section.case.string_appeared_here.this.section):
+        * wasm/references/anyref_globals.js:
+        * wasm/references/func_ref.js: Added.
+        (fullGC.gc.makeExportedFunction):
+        (makeExportedIdent):
+        (makeAnyfuncIdent):
+        (fun):
+        (assert.eq.instance.exports.fix.fun):
+        (assert.eq.instance.exports.fix):
+        (string_appeared_here.End.End.Function.End.Code.End.WebAssembly.imp.ref):
+        (string_appeared_here.End.End.Function.End.Code.End.WebAssembly):
+        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun):
+        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws):
+        (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly):
+        (assert.throws):
+        (assert.throws.doTest):
+        (let.importedFun.of):
+        (makeAnyfuncIdent.fun):
+        * wasm/references/validation.js:
+        (assert.throws):
+        * wasm/wasm.json:
+
 2019-06-17  Ross Kirsling  <ross.kirsl...@sony.com>
 
         Update test262 tests (2019.06.13)

Modified: trunk/JSTests/wasm/Builder.js (246503 => 246504)


--- trunk/JSTests/wasm/Builder.js	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/JSTests/wasm/Builder.js	2019-06-17 18:44:18 UTC (rev 246504)
@@ -536,6 +536,10 @@
                             s.data.push({ type, op: "get_global", mutability: _normalizeMutability(mutability), initValue });
                             return _errorHandlingProxyFor(globalBuilder);
                         },
+                        RefFunc: (type, initValue, mutability) => {
+                            s.data.push({ type, op: "ref.func", mutability: _normalizeMutability(mutability), initValue });
+                            return _errorHandlingProxyFor(globalBuilder);
+                        },
                         RefNull: (type, mutability) => {
                             s.data.push({ type, op: "ref.null", mutability: _normalizeMutability(mutability) });
                             return _errorHandlingProxyFor(globalBuilder);

Modified: trunk/JSTests/wasm/references/anyref_globals.js (246503 => 246504)


--- trunk/JSTests/wasm/references/anyref_globals.js	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/JSTests/wasm/references/anyref_globals.js	2019-06-17 18:44:18 UTC (rev 246504)
@@ -56,7 +56,9 @@
 
 const obj = { test: "hi" }
 
-$1.exports.set_glob(obj); assert.eq($1.exports.get_glob(), obj);
+assert.throws(() => $1.exports.expglob2 = null, TypeError, "Attempted to assign to readonly property.")
+
+$1.exports.set_glob(obj); assert.eq($1.exports.get_glob(), obj); assert.eq($1.exports.expglob2, "hi")
 $1.exports.set_glob(5); assert.eq($1.exports.get_glob(), 5)
 $1.exports.set_glob(null); assert.eq($1.exports.get_glob(), null)
 $1.exports.set_glob("hi"); assert.eq($1.exports.get_glob(), "hi")

Added: trunk/JSTests/wasm/references/func_ref.js (0 => 246504)


--- trunk/JSTests/wasm/references/func_ref.js	                        (rev 0)
+++ trunk/JSTests/wasm/references/func_ref.js	2019-06-17 18:44:18 UTC (rev 246504)
@@ -0,0 +1,447 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+fullGC()
+gc()
+
+function makeExportedFunction(i) {
+    const builder = (new Builder())
+          .Type().End()
+          .Function().End()
+          .Export()
+              .Function("h")
+          .End()
+          .Code()
+            .Function("h", { params: [], ret: "i32" }, [])
+              .I32Const(i)
+            .End()
+          .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const instance = new WebAssembly.Instance(module);
+
+    return instance.exports.h
+}
+
+function makeExportedIdent() {
+    const builder = (new Builder())
+          .Type().End()
+          .Function().End()
+          .Export()
+              .Function("h")
+          .End()
+          .Code()
+            .Function("h", { params: ["i32"], ret: "i32" }, [])
+              .GetLocal(0)
+            .End()
+          .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const instance = new WebAssembly.Instance(module);
+
+    return instance.exports.h
+}
+
+function makeAnyfuncIdent() {
+    const builder = (new Builder())
+          .Type().End()
+          .Function().End()
+          .Export()
+              .Function("h")
+          .End()
+          .Code()
+            .Function("h", { params: ["anyfunc"], ret: "anyfunc" }, [])
+              .GetLocal(0)
+            .End()
+          .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const instance = new WebAssembly.Instance(module);
+
+    return instance.exports.h
+}
+
+{
+    const myfun = makeExportedFunction(1337);
+    function fun() {
+        return 41;
+    }
+
+    const builder = (new Builder())
+          .Type().End()
+          .Function().End()
+          .Export()
+              .Function("h")
+              .Function("i")
+              .Function("get_h")
+              .Function("fix")
+              .Function("get_not_exported")
+              .Function("local_read")
+          .End()
+          .Code()
+            .Function("h", { params: ["anyfunc"], ret: "anyref" }, ["anyref"])
+              .GetLocal(0)
+              .SetLocal(1)
+              .GetLocal(1)
+            .End()
+
+            .Function("i", { params: ["anyfunc"], ret: "anyfunc" }, ["anyfunc"])
+              .GetLocal(0)
+              .SetLocal(1)
+              .GetLocal(1)
+            .End()
+
+            .Function("get_h", { params: [], ret: "anyfunc" }, ["anyfunc"])
+              .I32Const(0)
+              .RefFunc(0)
+              .SetLocal(0)
+              .If("anyfunc")
+              .Block("anyfunc", (b) =>
+                b.GetLocal(0)
+              )
+              .Else()
+              .Block("anyfunc", (b) =>
+                b.GetLocal(0)
+              )
+              .End()
+            .End()
+
+            .Function("fix", { params: [], ret: "anyfunc" }, [])
+              .RefFunc(3)
+            .End()
+
+            .Function("get_not_exported", { params: [], ret: "anyfunc" }, [])
+              .RefFunc(5)
+            .End()
+
+            .Function("ret_42", { params: [], ret: "i32" }, [])
+              .I32Const(42)
+            .End()
+
+            .Function("local_read", { params: [], ret: "i32" }, ["anyfunc"])
+              .GetLocal(0)
+              .RefIsNull()
+            .End()
+          .End();
+
+    const bin = builder.WebAssembly().get();
+    const module = new WebAssembly.Module(bin);
+    const instance = new WebAssembly.Instance(module);
+    fullGC();
+
+    assert.eq(instance.exports.local_read(), 1)
+    assert.eq(instance.exports.h(null), null)
+
+    assert.throws(() => instance.exports.h(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+    assert.eq(instance.exports.h(myfun), myfun)
+    assert.throws(() => instance.exports.h(5), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+    assert.throws(() => instance.exports.h(undefined), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+    assert.eq(instance.exports.i(null), null)
+    assert.eq(instance.exports.i(myfun), myfun)
+    assert.throws(() => instance.exports.i(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+    assert.throws(() => instance.exports.i(5), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+    assert.throws(() => instance.exports.get_h()(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+    assert.eq(instance.exports.get_h()(null), null)
+    assert.eq(instance.exports.get_h()(myfun), myfun)
+    assert.throws(() => instance.exports.get_h()(5), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+    assert.eq(instance.exports.get_not_exported()(), 42)
+
+    assert.eq(instance.exports.fix()(), instance.exports.fix());
+    assert.eq(instance.exports.fix(), instance.exports.fix);
+}
+
+// Globals
+
+{
+    const myfun = makeExportedFunction(42);
+    function fun() {
+        return 41;
+    }
+
+    const $1 = (() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Import()
+           .Global().Anyfunc("imp", "ref", "immutable").End()
+      .End()
+      .Function().End()
+      .Global()
+          .RefNull("anyfunc", "mutable")
+          .RefNull("anyfunc", "immutable")
+          .GetGlobal("anyfunc", 0, "mutable")
+          .RefFunc("anyfunc", 2, "immutable")
+      .End()
+      .Export()
+          .Function("set_glob")
+          .Function("get_glob")
+          .Function("glob_is_null")
+          .Function("set_glob_null")
+          .Function("get_import")
+          .Global("expglob", 2)
+          .Global("expglob2", 0)
+          .Global("exp_glob_is_null", 4)
+      .End()
+      .Code()
+        .Function("set_glob", { params: ["anyfunc"], ret: "void" })
+          .GetLocal(0)
+          .SetGlobal(1)
+        .End()
+
+        .Function("get_glob", { params: [], ret: "anyfunc" })
+            .GetGlobal(1)
+        .End()
+
+        .Function("glob_is_null", { params: [], ret: "i32" })
+            .Call(1)
+            .RefIsNull()
+        .End()
+
+        .Function("set_glob_null", { params: [], ret: "void" })
+            .RefNull()
+            .Call(0)
+        .End()
+
+        .Function("get_import", { params: [], ret: "anyfunc" })
+            .GetGlobal(0)
+        .End()
+      .End().WebAssembly().get()), { imp: { ref: makeExportedFunction(1337) } }))();
+
+    fullGC();
+
+    assert.eq($1.exports.get_import()(), 1337)
+    assert.eq($1.exports.expglob, null)
+    assert.eq($1.exports.expglob2(), 1337)
+    assert.eq($1.exports.exp_glob_is_null, $1.exports.glob_is_null);
+    assert.eq($1.exports.get_glob(), null)
+
+    $1.exports.set_glob(myfun); assert.eq($1.exports.get_glob(), myfun); assert.eq($1.exports.get_glob()(), 42); assert.eq($1.exports.expglob2(), 1337)
+    $1.exports.set_glob(null); assert.eq($1.exports.get_glob(), null)
+    $1.exports.set_glob(myfun); assert.eq($1.exports.get_glob()(), 42);
+
+    assert.throws(() => $1.exports.set_glob(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+    assert.eq($1.exports.glob_is_null(), 0)
+    $1.exports.set_glob_null(); assert.eq($1.exports.get_glob(), null)
+    assert.eq($1.exports.glob_is_null(), 1)
+}
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+  .Type().End()
+  .Import()
+       .Global().Anyfunc("imp", "ref", "immutable").End()
+  .End()
+  .Function().End()
+  .Code().End().WebAssembly().get()), { imp: { ref: function() { return "hi" } } }), Error, "imported global imp:ref must be a wasm exported function or null (evaluating 'new WebAssembly.Instance')");
+
+assert.throws(() => new WebAssembly.Module((new Builder())
+  .Type().End()
+  .Function().End()
+  .Code()
+    .Function("h", { params: ["anyfunc"], ret: "anyref" })
+      .GetLocal(0)
+    .End()
+  .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: control flow returns with unexpected type, in function at index 0 (evaluating 'new WebAssembly.Module')");
+
+assert.throws(() => new WebAssembly.Module((new Builder())
+  .Type().End()
+  .Function().End()
+  .Table()
+    .Table({initial: 1, element: "anyfunc"})
+  .End()
+  .Code()
+    .Function("h", { params: ["i32"], ret: "void" })
+      .GetLocal(0)
+      .I32Const(0)
+      .TableSet()
+    .End()
+  .End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module')");
+
+// Tables
+{
+    const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Function().End()
+      .Table()
+            .Table({initial: 1, element: "anyfunc"})
+      .End()
+      .Global()
+          .RefNull("anyfunc", "mutable")
+      .End()
+      .Export()
+          .Function("set_glob")
+          .Function("get_glob")
+          .Function("call_glob")
+          .Function("ret_20")
+      .End()
+      .Code()
+        .Function("set_glob", { params: ["anyfunc"], ret: "void" })
+          .GetLocal(0)
+          .SetGlobal(0)
+        .End()
+
+        .Function("get_glob", { params: [], ret: "anyfunc" })
+            .GetGlobal(0)
+        .End()
+
+        .Function("call_glob", { params: ["i32"], ret: "i32" })
+            .I32Const(0)
+            .GetGlobal(0)
+            .TableSet()
+
+            .GetLocal(0)
+            .I32Const(0)
+            .CallIndirect(2,0)
+        .End()
+
+        .Function("ret_20", { params: ["i32"], ret: "i32" })
+            .I32Const(20)
+        .End()
+      .End().WebAssembly().get()));
+
+    const myfun = makeExportedFunction(1337);
+    function fun(i) {
+        return 41;
+    }
+    const ident = makeExportedIdent();
+
+    $1.exports.set_glob($1.exports.ret_20); assert.eq($1.exports.get_glob(), $1.exports.ret_20); assert.eq($1.exports.call_glob(42), 20)
+    $1.exports.set_glob(null); assert.eq($1.exports.get_glob(), null); assert.throws(() => $1.exports.call_glob(42), Error, "call_indirect to a null table entry (evaluating 'func(...args)')")
+    $1.exports.set_glob(ident); assert.eq($1.exports.get_glob(), ident); assert.eq($1.exports.call_glob(42), 42)
+
+    assert.throws(() => $1.exports.set_glob(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+    $1.exports.set_glob(myfun); assert.eq($1.exports.get_glob(), myfun); assert.throws(() => $1.exports.call_glob(42), Error, "call_indirect to a signature that does not match (evaluating 'func(...args)')")
+
+    for (let i=0; i<1000; ++i) {
+        assert.throws(() => $1.exports.set_glob(function() {}), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')");
+    }
+}
+
+// Table set/get
+
+{
+    const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Function().End()
+      .Table()
+            .Table({initial: 1, element: "anyfunc"})
+      .End()
+      .Export()
+          .Function("set")
+          .Function("get")
+      .End()
+      .Code()
+        .Function("set", { params: ["anyfunc"], ret: "void" })
+          .I32Const(0)
+          .GetLocal(0)
+          .TableSet()
+        .End()
+
+        .Function("get", { params: [], ret: "anyfunc" })
+            .I32Const(0)
+            .TableGet()
+        .End()
+      .End().WebAssembly().get()));
+
+    function doSet() {
+        const myfun = makeExportedFunction(444);
+        for (let i=0; i<1000; ++i) {
+            $1.exports.set(myfun);
+        }
+        $1.exports.set(myfun); assert.eq($1.exports.get(), myfun); assert.eq($1.exports.get()(), 444);
+    }
+
+    function doTest(j,k, l) {
+        fullGC();
+        let garbage = { val: "hi", val2: 5, arr: [] }
+        for (let i=0; i<100; ++i) garbage.arr += ({ field: i + j + k + l })
+        fullGC();
+
+        for (let i=0; i<100; ++i) {
+            assert.eq($1.exports.get()(), 444);
+            fullGC();
+        }
+    }
+
+
+    doSet()
+    doTest(0,0,0)
+}
+
+// Wasm->JS Calls
+
+for (let importedFun of [function(i) { return i; }, makeAnyfuncIdent()]) {
+    const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Import()
+           .Function("imp", "h", { params: ["anyfunc"], ret: "anyfunc" })
+      .End()
+      .Function().End()
+      .Table()
+            .Table({initial: 1, element: "anyfunc"})
+      .End()
+      .Export()
+          .Function("test1")
+          .Function("test2")
+          .Function("test3")
+          .Function("test4")
+      .End()
+      .Code()
+        .Function("test1", { params: ["anyfunc"], ret: "anyfunc" })
+          .GetLocal(0)
+          .Call(0)
+        .End()
+
+        .Function("test2", { params: [], ret: "anyfunc" })
+          .RefFunc(1)
+          .Call(0)
+        .End()
+
+        .Function("test3", { params: ["anyfunc"], ret: "anyfunc" })
+          .GetLocal(0)
+          .I32Const(0)
+          .RefFunc(0)
+          .TableSet()
+          .I32Const(0)
+          .CallIndirect(0, 0)
+        .End()
+
+        .Function("test4", { params: [], ret: "anyfunc" })
+          .RefFunc(1)
+          .I32Const(0)
+          .RefFunc(0)
+          .TableSet()
+          .I32Const(0)
+          .CallIndirect(0, 0)
+        .End()
+      .End().WebAssembly().get()), { imp: { h: importedFun } });
+
+    const myfun = makeExportedFunction(1337);
+    function fun(i) {
+        return 41;
+    }
+
+    for (let test of [$1.exports.test1, $1.exports.test3]) {
+        assert.eq(test(myfun), myfun)
+        assert.eq(test(myfun)(), 1337)
+        assert.throws(() => test(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+        for (let i=0; i<1000; ++i) {
+            assert.throws(() => test(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+        }
+    }
+
+    for (let test of [$1.exports.test2, $1.exports.test4]) {
+        assert.eq(test(), $1.exports.test1)
+        assert.eq(test()(myfun), myfun)
+        assert.throws(() => test()(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+
+        for (let i=0; i<1000; ++i) {
+            assert.throws(() => test()(fun), Error, "Anyfunc must be an exported wasm function (evaluating 'func(...args)')")
+        }
+    }
+}

Modified: trunk/JSTests/wasm/references/validation.js (246503 => 246504)


--- trunk/JSTests/wasm/references/validation.js	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/JSTests/wasm/references/validation.js	2019-06-17 18:44:18 UTC (rev 246504)
@@ -63,7 +63,7 @@
     const bin = builder.WebAssembly();
     bin.trim();
 
-    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set expects the table to have type Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
+    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type Anyref expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
 }
 
 {
@@ -86,7 +86,7 @@
     const bin = builder.WebAssembly();
     bin.trim();
 
-    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.get expects the table to have type Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
+    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: control flow returns with unexpected type, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
 }
 
 {

Modified: trunk/JSTests/wasm/wasm.json (246503 => 246504)


--- trunk/JSTests/wasm/wasm.json	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/JSTests/wasm/wasm.json	2019-06-17 18:44:18 UTC (rev 246504)
@@ -11,13 +11,13 @@
         "i64":     { "type": "varint7", "value":  -2, "b3type": "B3::Int64" },
         "f32":     { "type": "varint7", "value":  -3, "b3type": "B3::Float" },
         "f64":     { "type": "varint7", "value":  -4, "b3type": "B3::Double" },
-        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
+        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
         "anyref":  { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
         "func":    { "type": "varint7", "value": -32, "b3type": "B3::Void" },
         "void":    { "type": "varint7", "value": -64, "b3type": "B3::Void" }
     },
-    "value_type": ["i32", "i64", "f32", "f64", "anyref"],
-    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
+    "value_type": ["i32", "i64", "f32", "f64", "anyref", "anyfunc"],
+    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref", "anyfunc"],
     "elem_type": ["anyfunc","anyref"],
     "external_kind": {
         "Function": { "type": "uint8", "value": 0 },
@@ -59,8 +59,9 @@
         "i64.const":           { "category": "special",    "value":  66, "return": ["i64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "varint64"}],                                             "description": "a constant value interpreted as i64" },
         "f64.const":           { "category": "special",    "value":  68, "return": ["f64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "double"}],                                               "description": "a constant value interpreted as f64" },
         "f32.const":           { "category": "special",    "value":  67, "return": ["f32"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "float"}],                                                "description": "a constant value interpreted as f32" },
-        "ref.null":            { "category": "special",    "value": 208, "return": ["anyref"],   "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
+        "ref.null":            { "category": "special",    "value": 208, "return": ["anyfunc"],  "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
         "ref.is_null":         { "category": "special",    "value": 209, "return": ["i32"],      "parameter": ["anyref"],               "immediate": [],                                                                                           "description": "determine if a reference is null" },
+        "ref.func":            { "category": "special",    "value": 210, "return": ["anyfunc"],  "parameter": [],                       "immediate": [{"name": "function_index",  "type": "varuint32"}],                                           "description": "return a reference to the function at the given index" },
         "get_local":           { "category": "special",    "value":  32, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "read a local variable or parameter" },
         "set_local":           { "category": "special",    "value":  33, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter" },
         "tee_local":           { "category": "special",    "value":  34, "return": ["any"],      "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter and return the same value" },

Modified: trunk/Source/_javascript_Core/ChangeLog (246503 => 246504)


--- trunk/Source/_javascript_Core/ChangeLog	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-06-17 18:44:18 UTC (rev 246504)
@@ -1,3 +1,86 @@
+2019-06-17  Justin Michaud  <justin_mich...@apple.com>
+
+        [WASM-References] Add support for Funcref in parameters and return types
+        https://bugs.webkit.org/show_bug.cgi?id=198157
+
+        Reviewed by Yusuke Suzuki.
+
+        Add support for funcref in parameters, globals, and in table.get/set. When converting a JSValue to 
+        a funcref (nee anyfunc), we first make sure it is an exported wasm function or null. 
+
+        We also add support for Ref.func. Anywhere a Ref.func is used, (statically) we construct a JS wrapper
+        for it so that we never need to construct JSValues when handling references. This should make threads
+        easier to implement.
+
+        Finally, we add some missing bounds checks for table.get/set.
+
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::tmpForType):
+        (JSC::Wasm::AirIRGenerator::moveOpForValueType):
+        (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+        (JSC::Wasm::AirIRGenerator::addLocal):
+        (JSC::Wasm::AirIRGenerator::addConstant):
+        (JSC::Wasm::AirIRGenerator::addRefFunc):
+        (JSC::Wasm::AirIRGenerator::addTableSet):
+        (JSC::Wasm::AirIRGenerator::setGlobal):
+        (JSC::Wasm::AirIRGenerator::addReturn):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::addLocal):
+        (JSC::Wasm::B3IRGenerator::addTableSet):
+        (JSC::Wasm::B3IRGenerator::addRefFunc):
+        (JSC::Wasm::B3IRGenerator::setGlobal):
+        * wasm/WasmBBQPlan.cpp:
+        (JSC::Wasm::BBQPlan::compileFunctions):
+        * wasm/WasmCallingConvention.h:
+        (JSC::Wasm::CallingConventionAir::marshallArgument const):
+        (JSC::Wasm::CallingConventionAir::setupCall const):
+        * wasm/WasmExceptionType.h:
+        * wasm/WasmFormat.h:
+        (JSC::Wasm::isValueType):
+        (JSC::Wasm::isSubtype):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+        * wasm/WasmInstance.cpp:
+        (JSC::Wasm::Instance::Instance):
+        (JSC::Wasm::Instance::getFunctionWrapper const):
+        (JSC::Wasm::Instance::setFunctionWrapper):
+        * wasm/WasmInstance.h:
+        * wasm/WasmModuleInformation.h:
+        (JSC::Wasm::ModuleInformation::referencedFunctions const):
+        (JSC::Wasm::ModuleInformation::addReferencedFunction const):
+        * wasm/WasmSectionParser.cpp:
+        (JSC::Wasm::SectionParser::parseGlobal):
+        (JSC::Wasm::SectionParser::parseInitExpr):
+        * wasm/WasmValidate.cpp:
+        (JSC::Wasm::Validate::addTableGet):
+        (JSC::Wasm::Validate::addTableSet):
+        (JSC::Wasm::Validate::addRefIsNull):
+        (JSC::Wasm::Validate::addRefFunc):
+        (JSC::Wasm::Validate::setLocal):
+        (JSC::Wasm::Validate::addCall):
+        (JSC::Wasm::Validate::addCallIndirect):
+        * wasm/js/JSToWasm.cpp:
+        (JSC::Wasm::createJSToWasmWrapper):
+        * wasm/js/JSWebAssemblyHelpers.h:
+        (JSC::isWebAssemblyHostFunction):
+        * wasm/js/JSWebAssemblyInstance.cpp:
+        (JSC::JSWebAssemblyInstance::visitChildren):
+        * wasm/js/JSWebAssemblyRuntimeError.cpp:
+        (JSC::createJSWebAssemblyRuntimeError):
+        * wasm/js/JSWebAssemblyRuntimeError.h:
+        * wasm/js/WasmToJS.cpp:
+        (JSC::Wasm::handleBadI64Use):
+        (JSC::Wasm::wasmToJS):
+        (JSC::Wasm::emitWasmToJSException):
+        * wasm/js/WasmToJS.h:
+        * wasm/js/WebAssemblyFunction.cpp:
+        (JSC::callWebAssemblyFunction):
+        (JSC::WebAssemblyFunction::jsCallEntrypointSlow):
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::link):
+        * wasm/wasm.json:
+
 2019-06-16  Darin Adler  <da...@apple.com>
 
         Rename AtomicString to AtomString

Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -234,10 +234,11 @@
 
     // References
     PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
 
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -370,6 +371,7 @@
             return g32();
         case Type::I64:
         case Type::Anyref:
+        case Type::Anyfunc:
             return g64();
         case Type::F32:
             return f32();
@@ -554,6 +556,7 @@
             return Move32;
         case Type::I64:
         case Type::Anyref:
+        case Type::Anyfunc:
             return Move;
         case Type::F32:
             return MoveFloat;
@@ -799,6 +802,7 @@
             break;
         case Type::I64:
         case Type::Anyref:
+        case Type::Anyfunc:
             append(Move, arg, m_locals[i]);
             break;
         case Type::F32:
@@ -884,6 +888,7 @@
         m_locals.uncheckedAppend(local);
         switch (type) {
         case Type::Anyref:
+        case Type::Anyfunc:
             append(Move, Arg::imm(JSValue::encode(jsNull())), local);
             break;
         case Type::I32:
@@ -918,6 +923,7 @@
     case Type::I32:
     case Type::I64:
     case Type::Anyref:
+    case Type::Anyfunc:
         append(block, Move, Arg::bigImm(value), result);
         break;
     case Type::F32:
@@ -953,36 +959,47 @@
     return { };
 }
 
-auto AirIRGenerator::addTableGet(ExpressionType& idx, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
-    ASSERT(idx.tmp());
-    ASSERT(idx.type() == Type::I32);
+    result = tmpForType(Type::Anyfunc);
+    emitCCall(&doWasmRefFunc, result, instanceValue(), addConstant(Type::I32, index));
+
+    return { };
+}
+
+auto AirIRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
+{
+    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
+    ASSERT(index.tmp());
+    ASSERT(index.type() == Type::I32);
     result = tmpForType(Type::Anyref);
 
-    uint64_t (*doGet)(Instance*, int32_t) = [] (Instance* instance, int32_t idx) -> uint64_t {
-        return JSValue::encode(instance->table()->get(idx));
-    };
+    emitCCall(&getWasmTableElement, result, instanceValue(), index);
+    emitCheck([&] {
+        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
+    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
+    });
 
-    emitCCall(doGet, result, instanceValue(), idx);
-
     return { };
 }
 
-auto AirIRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> PartialResult
+auto AirIRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
-    ASSERT(idx.tmp());
-    ASSERT(idx.type() == Type::I32);
+    ASSERT(index.tmp());
+    ASSERT(index.type() == Type::I32);
     ASSERT(value.tmp());
 
-    void (*doSet)(Instance*, int32_t, uint64_t value) = [] (Instance* instance, int32_t idx, uint64_t value) -> void {
-        // FIXME: We need to box wasm Funcrefs once they are supported here.
-        // <https://bugs.webkit.org/show_bug.cgi?id=198157>
-        instance->table()->set(idx, JSValue::decode(value));
-    };
+    auto shouldThrow = g32();
+    emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), index, value);
 
-    emitCCall(doSet, TypedTmp(), instanceValue(), idx, value);
+    emitCheck([&] {
+        return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), shouldThrow, shouldThrow);
+    }, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+        this->emitThrowException(jit, ExceptionType::OutOfBoundsTableAccess);
+    });
 
     return { };
 }
@@ -1103,7 +1120,7 @@
         append(moveOpForValueType(type), value, Arg::addr(temp));
     }
 
-    if (type == Anyref)
+    if (isSubtype(type, Anyref))
         emitWriteBarrierForJSWrapper();
 
     return { };
@@ -1623,6 +1640,7 @@
             break;
         case Type::I64:
         case Type::Anyref:
+        case Type::Anyfunc:
             append(Move, returnValues[0], returnValueGPR);
             append(Ret64, returnValueGPR);
             break;

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -187,10 +187,11 @@
 
     // References
     PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
-    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
 
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -538,7 +539,7 @@
     for (uint32_t i = 0; i < count; ++i) {
         Variable* local = m_proc.addVariable(toB3Type(type));
         m_locals.uncheckedAppend(local);
-        auto val = type == Anyref ? JSValue::encode(jsNull()) : 0;
+        auto val = isSubtype(type, Anyref) ? JSValue::encode(jsNull()) : 0;
         m_currentBlock->appendNew<VariableValue>(m_proc, Set, Origin(), local, constant(toB3Type(type), val, Origin()));
     }
     return { };
@@ -565,36 +566,55 @@
     return { };
 }
 
-auto B3IRGenerator::addTableGet(ExpressionType& idx, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
-    uint64_t (*doGet)(Instance*, int32_t) = [] (Instance* instance, int32_t idx) -> uint64_t {
-        return JSValue::encode(instance->table()->get(idx));
-    };
-
     result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(Anyref), origin(),
-        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doGet, B3CCallPtrTag)),
-        instanceValue(), idx);
+        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&getWasmTableElement, B3CCallPtrTag)),
+        instanceValue(), index);
 
+    {
+        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
+            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), result, m_currentBlock->appendNew<Const64Value>(m_proc, origin(), 0)));
+
+        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
+        });
+    }
+
     return { };
 }
 
-auto B3IRGenerator::addTableSet(ExpressionType& idx, ExpressionType& value) -> PartialResult
+auto B3IRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
 {
     // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
-    void (*doSet)(Instance*, int32_t, uint64_t value) = [] (Instance* instance, int32_t idx, uint64_t value) -> void {
-        // FIXME: We need to box wasm Funcrefs once they are supported here.
-        // <https://bugs.webkit.org/show_bug.cgi?id=198157>
-        instance->table()->set(idx, JSValue::decode(value));
-    };
+    auto shouldThrow = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int32, origin(),
+        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&setWasmTableElement, B3CCallPtrTag)),
+        instanceValue(), index, value);
 
-    m_currentBlock->appendNew<CCallValue>(m_proc, B3::Void, origin(),
-        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doSet, B3CCallPtrTag)),
-        instanceValue(), idx, value);
+    {
+        CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
+            m_currentBlock->appendNew<Value>(m_proc, Equal, origin(), shouldThrow, m_currentBlock->appendNew<Const32Value>(m_proc, origin(), 0)));
 
+        check->setGenerator([=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+            this->emitExceptionCheck(jit, ExceptionType::OutOfBoundsTableAccess);
+        });
+    }
+
     return { };
 }
 
+auto B3IRGenerator::addRefFunc(uint32_t index, ExpressionType& result) -> PartialResult
+{
+    // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
+
+    result = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int64, origin(),
+        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&doWasmRefFunc, B3CCallPtrTag)),
+        instanceValue(), addConstant(Type::I32, index));
+
+    return { };
+}
+
 auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
 {
     ASSERT(m_locals[index]);
@@ -679,7 +699,7 @@
     Value* globalsArray = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(), instanceValue(), safeCast<int32_t>(Instance::offsetOfGlobals()));
     m_currentBlock->appendNew<MemoryValue>(m_proc, Store, origin(), value, globalsArray, safeCast<int32_t>(index * sizeof(Register)));
 
-    if (m_info.globals[index].type == Anyref)
+    if (isSubtype(m_info.globals[index].type, Anyref))
         emitWriteBarrierForJSWrapper();
 
     return { };

Modified: trunk/Source/_javascript_Core/wasm/WasmBBQPlan.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmBBQPlan.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmBBQPlan.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -286,7 +286,7 @@
 
         m_wasmInternalFunctions[functionIndex] = WTFMove(*parseAndCompileResult);
 
-        if (m_exportedFunctionIndices.contains(functionIndex)) {
+        if (m_exportedFunctionIndices.contains(functionIndex) || m_moduleInformation->referencedFunctions().contains(functionIndex)) {
             auto locker = holdLock(m_lock);
             auto result = m_embedderToWasmInternalFunctions.add(functionIndex, m_createEmbedderWrapper(m_compilationContexts[functionIndex], signature, &m_unlinkedWasmToWasmCalls[functionIndex], m_moduleInformation.get(), m_mode, functionIndex));
             ASSERT_UNUSED(result, result.isNewEntry);

Modified: trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmCallingConvention.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -236,6 +236,7 @@
         case Type::I32:
         case Type::I64:
         case Type::Anyref:
+        case Wasm::Anyfunc:
             marshallArgumentImpl(m_gprArgs, gpArgumentCount, stackOffset, regFunc, stackFunc);
             break;
         case Type::F32:
@@ -301,6 +302,7 @@
         case Type::I32:
         case Type::I64:
         case Type::Anyref:
+        case Wasm::Anyfunc:
             patchpoint->resultConstraint = B3::ValueRep::reg(GPRInfo::returnValueGPR);
             break;
         default:

Modified: trunk/Source/_javascript_Core/wasm/WasmExceptionType.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmExceptionType.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmExceptionType.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -33,6 +33,7 @@
 
 #define FOR_EACH_EXCEPTION(macro) \
     macro(OutOfBoundsMemoryAccess,  "Out of bounds memory access") \
+    macro(OutOfBoundsTableAccess,  "Out of bounds table access") \
     macro(OutOfBoundsCallIndirect, "Out of bounds call_indirect") \
     macro(NullTableEntry,  "call_indirect to a null table entry") \
     macro(BadSignature, "call_indirect to a signature that does not match") \
@@ -42,7 +43,8 @@
     macro(IntegerOverflow, "Integer overflow") \
     macro(StackOverflow, "Stack overflow") \
     macro(I64ArgumentType, "WebAssembly function with an i64 argument can't be called from _javascript_") \
-    macro(I64ReturnType, "WebAssembly function that returns i64 can't be called from _javascript_")
+    macro(I64ReturnType, "WebAssembly function that returns i64 can't be called from _javascript_") \
+    macro(FuncrefNotWasm, "Anyfunc must be an exported wasm function")
 
 enum class ExceptionType : uint32_t {
 #define MAKE_ENUM(enumName, error) enumName,

Modified: trunk/Source/_javascript_Core/wasm/WasmFormat.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmFormat.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmFormat.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -68,6 +68,7 @@
     case F64:
         return true;
     case Anyref:
+    case Anyfunc:
         return Options::useWebAssemblyReferences();
     default:
         break;
@@ -74,6 +75,13 @@
     }
     return false;
 }
+
+inline bool isSubtype(Type sub, Type parent)
+{
+    if (sub == parent)
+        return true;
+    return sub == Anyfunc && parent == Anyref;
+}
     
 enum class ExternalKind : uint8_t {
     // FIXME auto-generate this. https://bugs.webkit.org/show_bug.cgi?id=165231
@@ -138,6 +146,7 @@
     enum InitializationType {
         IsImport,
         FromGlobalImport,
+        FromRefFunc,
         FromExpression
     };
 
@@ -234,6 +243,7 @@
     uint32_t initial() const { return m_initial; }
     Optional<uint32_t> maximum() const { return m_maximum; }
     TableElementType type() const { return m_type; }
+    Wasm::Type wasmType() const { return m_type == TableElementType::Funcref ? Type::Anyfunc : Type::Anyref; }
 
 private:
     uint32_t m_initial;

Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -283,9 +283,9 @@
 
     case TableGet: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        ExpressionType result, idx;
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.get");
-        WASM_TRY_ADD_TO_CONTEXT(addTableGet(idx, result));
+        ExpressionType result, index;
+        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.get");
+        WASM_TRY_ADD_TO_CONTEXT(addTableGet(index, result));
         m_expressionStack.append(result);
         return { };
     }
@@ -292,16 +292,16 @@
 
     case TableSet: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        ExpressionType val, idx;
+        ExpressionType val, index;
         WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
-        WASM_TRY_POP_EXPRESSION_STACK_INTO(idx, "table.set");
-        WASM_TRY_ADD_TO_CONTEXT(addTableSet(idx, val));
+        WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.set");
+        WASM_TRY_ADD_TO_CONTEXT(addTableSet(index, val));
         return { };
     }
 
     case RefNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        m_expressionStack.append(m_context.addConstant(Anyref, JSValue::encode(jsNull())));
+        m_expressionStack.append(m_context.addConstant(Anyfunc, JSValue::encode(jsNull())));
         return { };
     }
 
@@ -314,6 +314,17 @@
         return { };
     }
 
+    case RefFunc: {
+        uint32_t index;
+        ExpressionType result;
+        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get index for ref.func");
+
+        WASM_TRY_ADD_TO_CONTEXT(addRefFunc(index, result));
+        m_expressionStack.append(result);
+        return { };
+    }
+
     case GetLocal: {
         uint32_t index;
         ExpressionType result;
@@ -681,6 +692,13 @@
         return { };
     }
 
+    case RefFunc: {
+        uint32_t unused;
+        WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get immediate for ", m_currentOpcode, " in unreachable context");
+        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+        return { };
+    }
+
     case GrowMemory:
     case CurrentMemory: {
         uint8_t reserved;

Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmInstance.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -29,6 +29,7 @@
 #if ENABLE(WEBASSEMBLY)
 
 #include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
 #include "JSWebAssemblyInstance.h"
 #include "Register.h"
 #include "WasmModuleInformation.h"
@@ -57,7 +58,7 @@
         new (importFunctionInfo(i)) ImportFunctionInfo();
     memset(static_cast<void*>(m_globals.get()), 0, globalMemoryByteSize(m_module.get()));
     for (unsigned i = 0; i < m_module->moduleInformation().globals.size(); ++i) {
-        if (m_module.get().moduleInformation().globals[i].type == Anyref)
+        if (isSubtype(m_module.get().moduleInformation().globals[i].type, Anyref))
             m_globalsToMark.set(i);
     }
 }
@@ -80,6 +81,75 @@
     m_globals.get()[i].anyref.set(*owner<JSWebAssemblyInstance>()->vm(), owner<JSWebAssemblyInstance>(), value);
 }
 
+JSValue Instance::getFunctionWrapper(unsigned i) const
+{
+    JSValue value = m_functionWrappers.get(i).get();
+    if (value.isEmpty())
+        return jsNull();
+    return value;
+}
+
+void Instance::setFunctionWrapper(unsigned i, JSValue value)
+{
+    ASSERT(m_owner);
+    ASSERT(value.isFunction(*owner<JSWebAssemblyInstance>()->vm()));
+    ASSERT(!m_functionWrappers.contains(i));
+    auto locker = holdLock(owner<JSWebAssemblyInstance>()->cellLock());
+    m_functionWrappers.set(i, WriteBarrier<Unknown>(*owner<JSWebAssemblyInstance>()->vm(), owner<JSWebAssemblyInstance>(), value));
+    ASSERT(getFunctionWrapper(i) == value);
+}
+
+EncodedJSValue getWasmTableElement(Instance* instance, int32_t signedIndex)
+{
+    if (signedIndex < 0)
+        return 0;
+
+    uint32_t index = signedIndex;
+    if (index >= instance->table()->length())
+        return 0;
+
+    return JSValue::encode(instance->table()->get(index));
+}
+
+bool setWasmTableElement(Instance* instance, int32_t signedIndex, EncodedJSValue encValue)
+{
+    if (signedIndex < 0)
+        return false;
+
+    uint32_t index = signedIndex;
+    if (index >= instance->table()->length())
+        return false;
+
+    JSValue value = JSValue::decode(encValue);
+    if (instance->table()->type() == Wasm::TableElementType::Anyref)
+        instance->table()->set(index, value);
+    else if (instance->table()->type() == Wasm::TableElementType::Funcref) {
+        WebAssemblyFunction* wasmFunction;
+        WebAssemblyWrapperFunction* wasmWrapperFunction;
+
+        if (isWebAssemblyHostFunction(*instance->owner<JSObject>()->vm(), value, wasmFunction, wasmWrapperFunction)) {
+            ASSERT(!!wasmFunction || !!wasmWrapperFunction);
+            if (wasmFunction)
+                instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
+            else
+                instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
+        } else if (value.isNull())
+            instance->table()->clear(index);
+        else
+            ASSERT_NOT_REACHED();
+    } else
+        ASSERT_NOT_REACHED();
+
+    return true;
+}
+
+EncodedJSValue doWasmRefFunc(Instance* instance, uint32_t index)
+{
+    JSValue value = instance->getFunctionWrapper(index);
+    ASSERT(value.isFunction(*instance->owner<JSObject>()->vm()));
+    return JSValue::encode(value);
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmInstance.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -39,10 +39,16 @@
 namespace JSC { namespace Wasm {
 
 struct Context;
+class Instance;
 
+EncodedJSValue getWasmTableElement(Instance*, int32_t);
+bool setWasmTableElement(Instance*, int32_t, EncodedJSValue encValue);
+EncodedJSValue doWasmRefFunc(Instance*, uint32_t);
+
 class Instance : public ThreadSafeRefCounted<Instance>, public CanMakeWeakPtr<Instance> {
 public:
     using StoreTopCallFrameCallback = WTF::Function<void(void*)>;
+    using FunctionWrapperMap = HashMap<uint32_t, WriteBarrier<Unknown>, IntHash<uint32_t>, WTF::UnsignedWithZeroKeyHashTraits<uint32_t>>;
 
     static Ref<Instance> create(Context*, Ref<Module>&&, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&&);
 
@@ -91,6 +97,9 @@
     void setGlobal(unsigned i, int64_t bits) { m_globals.get()[i].primitive = bits; }
     void setGlobal(unsigned, JSValue);
     const BitVector& globalsToMark() { return m_globalsToMark; }
+    JSValue getFunctionWrapper(unsigned) const;
+    typename FunctionWrapperMap::ValuesConstIteratorRange functionWrappers() const { return m_functionWrappers.values(); }
+    void setFunctionWrapper(unsigned, JSValue);
 
     static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
     static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(Instance, m_globals); }
@@ -159,6 +168,7 @@
         uint64_t primitive;
     };
     MallocPtr<GlobalValue> m_globals;
+    FunctionWrapperMap m_functionWrappers;
     BitVector m_globalsToMark;
     EntryFrame** m_pointerToTopEntryFrame { nullptr };
     void** m_pointerToActualStackLimit { nullptr };

Modified: trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -29,6 +29,7 @@
 
 #include "WasmFormat.h"
 
+#include <wtf/BitVector.h>
 #include <wtf/Optional.h>
 
 namespace JSC { namespace Wasm {
@@ -66,6 +67,9 @@
     uint32_t memoryCount() const { return memory ? 1 : 0; }
     uint32_t tableCount() const { return tableInformation ? 1 : 0; }
 
+    const BitVector& referencedFunctions() const { return m_referencedFunctions; }
+    void addReferencedFunction(unsigned index) const { m_referencedFunctions.set(index); }
+
     Vector<Import> imports;
     Vector<SignatureIndex> importFunctionSignatureIndices;
     Vector<SignatureIndex> internalFunctionSignatureIndices;
@@ -84,6 +88,8 @@
     unsigned firstInternalGlobal { 0 };
     Vector<CustomSection> customSections;
     Ref<NameSection> nameSection;
+    
+    mutable BitVector m_referencedFunctions;
 };
 
     

Modified: trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -291,9 +291,11 @@
         WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, global.initialBitsOrImportNumber, typeForInitOpcode));
         if (initOpcode == GetGlobal)
             global.initializationType = Global::FromGlobalImport;
+        else if (initOpcode == RefFunc)
+            global.initializationType = Global::FromRefFunc;
         else
             global.initializationType = Global::FromExpression;
-        WASM_PARSER_FAIL_IF(typeForInitOpcode != global.type, "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
+        WASM_PARSER_FAIL_IF(!isSubtype(typeForInitOpcode, global.type), "Global init_expr opcode of type ", typeForInitOpcode, " doesn't match global's type ", global.type);
 
         m_info->globals.uncheckedAppend(WTFMove(global));
     }
@@ -479,11 +481,21 @@
     }
 
     case RefNull: {
-        resultType = Anyref;
+        resultType = Anyfunc;
         bitsOrImportNumber = JSValue::encode(jsNull());
         break;
     }
 
+    case RefFunc: {
+        uint32_t index;
+        WASM_PARSER_FAIL_IF(!parseVarUInt32(index), "can't get ref.func index");
+        WASM_PARSER_FAIL_IF(index >= m_info->functions.size(), "ref.func index", index, " exceeds the number of functions ", m_info->functions.size());
+
+        resultType = Anyfunc;
+        bitsOrImportNumber = index;
+        break;
+    }
+
     default:
         WASM_PARSER_FAIL_IF(true, "unknown init_expr opcode ", opcode);
     }

Modified: trunk/Source/_javascript_Core/wasm/WasmValidate.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/WasmValidate.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/WasmValidate.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -103,10 +103,11 @@
 
     // References
     Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
 
     // Tables
-    Result WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
-    Result WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+    Result WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
 
     // Locals
     Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -177,20 +178,21 @@
     return { };
 }
 
-auto Validate::addTableGet(ExpressionType& idx, ExpressionType& result) -> Result
+auto Validate::addTableGet(ExpressionType& index, ExpressionType& result) -> Result
 {
-    result = Type::Anyref;
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != idx, "table.get index to type ", idx, " expected ", Type::I32);
-    WASM_VALIDATOR_FAIL_IF(TableElementType::Anyref != m_module.tableInformation.type(), "table.get expects the table to have type ", Type::Anyref);
+    result = m_module.tableInformation.wasmType();
+    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", index, " expected ", Type::I32);
 
     return { };
 }
 
-auto Validate::addTableSet(ExpressionType& idx, ExpressionType& value) -> Result
+auto Validate::addTableSet(ExpressionType& index, ExpressionType& value) -> Result
 {
-    WASM_VALIDATOR_FAIL_IF(Type::I32 != idx, "table.set index to type ", idx, " expected ", Type::I32);
-    WASM_VALIDATOR_FAIL_IF(Type::Anyref != value, "table.set value to type ", value, " expected ", Type::Anyref);
-    WASM_VALIDATOR_FAIL_IF(TableElementType::Anyref != m_module.tableInformation.type(), "table.set expects the table to have type ", Type::Anyref);
+    auto type = m_module.tableInformation.wasmType();
+    WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
+    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
+    WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Anyref
+        && m_module.tableInformation.type() != TableElementType::Funcref, "table.set expects the table to have type anyref or anyfunc");
 
     return { };
 }
@@ -198,11 +200,20 @@
 auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
 {
     result = Type::I32;
-    WASM_VALIDATOR_FAIL_IF(Type::Anyref != value, "ref.is_null to type ", value, " expected ", Type::Anyref);
+    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, Type::Anyref), "ref.is_null to type ", value, " expected ", Type::Anyref);
 
     return { };
 }
 
+auto Validate::addRefFunc(uint32_t index, ExpressionType& result) -> Result
+{
+    result = Type::Anyfunc;
+    WASM_VALIDATOR_FAIL_IF(index >= m_module.functionIndexSpaceSize(), "ref.func index ", index, " is too large, max is ", m_module.functionIndexSpaceSize());
+    m_module.addReferencedFunction(index);
+
+    return { };
+}
+
 auto Validate::addLocal(Type type, uint32_t count) -> Result
 {
     size_t size = m_locals.size() + count;
@@ -224,7 +235,7 @@
 {
     ExpressionType localType;
     WASM_FAIL_IF_HELPER_FAILS(getLocal(index, localType));
-    WASM_VALIDATOR_FAIL_IF(localType != value, "set_local to type ", value, " expected ", localType);
+    WASM_VALIDATOR_FAIL_IF(!isSubtype(value, localType), "set_local to type ", value, " expected ", localType);
     return { };
 }
 
@@ -362,7 +373,7 @@
     WASM_VALIDATOR_FAIL_IF(signature.argumentCount() != args.size(), "arity mismatch in call, got ", args.size(), " arguments, expected ", signature.argumentCount());
 
     for (unsigned i = 0; i < args.size(); ++i)
-        WASM_VALIDATOR_FAIL_IF(args[i] != signature.argument(i), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call, got ", args[i], ", expected ", signature.argument(i));
 
     result = signature.returnType();
     return { };
@@ -375,7 +386,7 @@
     WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
 
     for (unsigned i = 0; i < argumentCount; ++i)
-        WASM_VALIDATOR_FAIL_IF(args[i] != signature.argument(i), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
+        WASM_VALIDATOR_FAIL_IF(!isSubtype(args[i], signature.argument(i)), "argument type mismatch in call_indirect, got ", args[i], ", expected ", signature.argument(i));
 
     WASM_VALIDATOR_FAIL_IF(args.last() != I32, "non-i32 call_indirect index ", args.last());
 

Modified: trunk/Source/_javascript_Core/wasm/js/JSToWasm.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/JSToWasm.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/JSToWasm.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -31,6 +31,7 @@
 #include "CCallHelpers.h"
 #include "DisallowMacroScratchRegisterUsage.h"
 #include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyRuntimeError.h"
 #include "MaxFrameExtentForSlowPathCall.h"
@@ -83,6 +84,7 @@
             FALLTHROUGH;
         case Wasm::I32:
         case Wasm::Anyref:
+        case Wasm::Anyfunc:
             if (numGPRs >= wasmCallingConvention().m_gprArgs.size())
                 totalFrameSize += sizeof(void*);
             ++numGPRs;
@@ -122,20 +124,7 @@
             jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, JSWebAssemblyInstance::offsetOfInstance()), GPRInfo::argumentGPR2);
         }
 
-        jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR2, Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
-        jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
-        jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
-        jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
-        jit.move(CCallHelpers::TrustedImm32(static_cast<int32_t>(argumentsIncludeI64 ? ExceptionType::I64ArgumentType : ExceptionType::I64ReturnType)), GPRInfo::argumentGPR1);
-
-        CCallHelpers::Call call = jit.call(OperationPtrTag);
-
-        jit.jump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
-        jit.breakpoint(); // We should not reach this.
-
-        jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
-            linkBuffer.link(call, FunctionPtr<OperationPtrTag>(wasmToJSException));
-        });
+        emitThrowWasmToJSException(jit, GPRInfo::argumentGPR2, argumentsIncludeI64 ? ExceptionType::I64ArgumentType : ExceptionType::I64ReturnType);
         return result;
     }
 
@@ -165,6 +154,7 @@
             switch (signature.argument(i)) {
             case Wasm::I32:
             case Wasm::I64:
+            case Wasm::Anyfunc:
             case Wasm::Anyref:
                 if (numGPRs >= wasmCallingConvention().m_gprArgs.size()) {
                     if (signature.argument(i) == Wasm::I32) {
@@ -250,7 +240,7 @@
         jit.moveTrustedValue(jsUndefined(), JSValueRegs { GPRInfo::returnValueGPR });
         break;
     case Wasm::Anyref:
-        // FIXME: We need to box wasm Funcrefs once they are supported here.
+    case Wasm::Anyfunc:
         break;
     case Wasm::I32:
         jit.zeroExtend32ToPtr(GPRInfo::returnValueGPR, GPRInfo::returnValueGPR);
@@ -268,7 +258,6 @@
     }
     case Wasm::I64:
     case Wasm::Func:
-    case Wasm::Anyfunc:
         jit.breakpoint();
         break;
     default:

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -122,7 +122,7 @@
 }
 
 
-ALWAYS_INLINE bool isWebAssemblyHostFunction(VM& vm, JSObject* object)
+ALWAYS_INLINE bool isWebAssemblyHostFunction(VM& vm, JSValue object)
 {
     WebAssemblyFunction* unused;
     WebAssemblyWrapperFunction* unused2;

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -91,11 +91,12 @@
     for (unsigned i = 0; i < thisObject->instance().numImportFunctions(); ++i)
         visitor.append(*thisObject->instance().importFunction<WriteBarrier<JSObject>>(i)); // This also keeps the functions' JSWebAssemblyInstance alive.
 
-    for (size_t i : thisObject->instance().globalsToMark()) {
-        // FIXME: We need to box wasm Funcrefs once they are supported here.
-        // <https://bugs.webkit.org/show_bug.cgi?id=198157>
+    for (size_t i : thisObject->instance().globalsToMark())
         visitor.appendUnbarriered(JSValue::decode(thisObject->instance().loadI64Global(i)));
-    }
+
+    auto locker = holdLock(cell->cellLock());
+    for (auto& wrapper : thisObject->instance().functionWrappers())
+        visitor.appendUnbarriered(wrapper.get());
 }
 
 void JSWebAssemblyInstance::finalizeCreation(VM& vm, ExecState* exec, Ref<Wasm::CodeBlock>&& wasmCodeBlock, JSObject* importObject, Wasm::CreationMode creationMode)

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -48,6 +48,12 @@
 
 const ClassInfo JSWebAssemblyRuntimeError::s_info = { "WebAssembly.RuntimeError", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSWebAssemblyRuntimeError) };
 
+JSObject* createJSWebAssemblyRuntimeError(ExecState* exec, VM& vm, const String& message)
+{
+    ASSERT(!message.isEmpty());
+    JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+    return JSWebAssemblyRuntimeError::create(exec, vm, globalObject->webAssemblyRuntimeErrorStructure(), message);
+}
     
 } // namespace JSC
 

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyRuntimeError.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -43,6 +43,8 @@
     JSWebAssemblyRuntimeError(VM&, Structure*);
 };
 
+JSObject* createJSWebAssemblyRuntimeError(ExecState*, VM&, const String&);
+
 } // namespace JSC
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/WasmToJS.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -32,6 +32,7 @@
 #include "FrameTracers.h"
 #include "JITExceptions.h"
 #include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
 #include "JSWebAssemblyInstance.h"
 #include "JSWebAssemblyRuntimeError.h"
 #include "LinkBuffer.h"
@@ -65,7 +66,6 @@
         switch (argType) {
         case Void:
         case Func:
-        case Anyfunc:
             RELEASE_ASSERT_NOT_REACHED();
 
         case I64: {
@@ -162,10 +162,10 @@
             switch (argType) {
             case Void:
             case Func:
-            case Anyfunc:
             case I64:
                 RELEASE_ASSERT_NOT_REACHED();
             case Anyref:
+            case Anyfunc:
             case I32: {
                 GPRReg gprReg;
                 if (marshalledGPRs < wasmCC.m_gprArgs.size())
@@ -237,14 +237,17 @@
                     switch (argType) {
                     case Void:
                     case Func:
-                    case Anyfunc:
                     case I64:
                         RELEASE_ASSERT_NOT_REACHED();
                     case I32:
                         arg = jsNumber(static_cast<int32_t>(buffer[argNum]));
                         break;
+                    case Anyfunc: {
+                        arg = JSValue::decode(buffer[argNum]);
+                        ASSERT(isWebAssemblyHostFunction(*vm, arg) || arg.isNull());
+                        break;
+                    }
                     case Anyref:
-                        // FIXME: We need to box wasm Funcrefs once they are supported here.
                         arg = JSValue::decode(buffer[argNum]);
                         break;
                     case F32:
@@ -268,7 +271,6 @@
                 uint64_t realResult;
                 switch (signature.returnType()) {
                 case Func:
-                case Anyfunc:
                 case I64:
                     RELEASE_ASSERT_NOT_REACHED();
                     break;
@@ -278,6 +280,11 @@
                     realResult = static_cast<uint64_t>(static_cast<uint32_t>(result.toInt32(exec)));
                     break;
                 }
+                case Anyfunc: {
+                    realResult = JSValue::encode(result);
+                    ASSERT(result.isFunction(*vm) || result.isNull());
+                    break;
+                }
                 case Anyref: {
                     realResult = JSValue::encode(result);
                     break;
@@ -371,10 +378,10 @@
             switch (argType) {
             case Void:
             case Func:
-            case Anyfunc:
             case I64:
                 RELEASE_ASSERT_NOT_REACHED(); // Handled above.
             case Anyref:
+            case Anyfunc:
             case I32: {
                 GPRReg gprReg;
                 if (marshalledGPRs < wasmCC.m_gprArgs.size())
@@ -390,7 +397,6 @@
                     jit.zeroExtend32ToPtr(gprReg, gprReg); // Clear non-int32 and non-tag bits.
                     jit.boxInt32(gprReg, JSValueRegs(gprReg), DoNotHaveTagRegisters);
                 }
-                // FIXME: We need to box wasm Funcrefs once they are supported here.
                 jit.store64(gprReg, calleeFrame.withOffset(calleeFrameOffset));
                 calleeFrameOffset += sizeof(Register);
                 break;
@@ -441,10 +447,10 @@
             switch (argType) {
             case Void:
             case Func:
-            case Anyfunc:
             case I64:
                 RELEASE_ASSERT_NOT_REACHED(); // Handled above.
             case Anyref:
+            case Anyfunc:
             case I32:
                 // Skipped: handled above.
                 if (marshalledGPRs >= wasmCC.m_gprArgs.size())
@@ -519,7 +525,6 @@
         // Discard.
         break;
     case Func:
-    case Anyfunc:
         // For the _javascript_ embedding, imports with these types in their signature return are a WebAssembly.Module validation error.
         RELEASE_ASSERT_NOT_REACHED();
         break;
@@ -553,6 +558,7 @@
         done.link(&jit);
         break;
     }
+    case Anyfunc:
     case Anyref:
         break;
     case F32: {
@@ -695,6 +701,25 @@
     return vm.targetMachinePCForThrow;
 }
 
+void emitThrowWasmToJSException(CCallHelpers& jit, GPRReg wasmInstance, Wasm::ExceptionType type)
+{
+    ASSERT(wasmInstance != GPRInfo::argumentGPR0);
+    jit.loadPtr(CCallHelpers::Address(wasmInstance, Wasm::Instance::offsetOfPointerToTopEntryFrame()), GPRInfo::argumentGPR0);
+    jit.loadPtr(CCallHelpers::Address(GPRInfo::argumentGPR0), GPRInfo::argumentGPR0);
+    jit.copyCalleeSavesToEntryFrameCalleeSavesBuffer(GPRInfo::argumentGPR0);
+    jit.move(GPRInfo::callFrameRegister, GPRInfo::argumentGPR0);
+    jit.move(CCallHelpers::TrustedImm32(static_cast<int32_t>(type)), GPRInfo::argumentGPR1);
+
+    CCallHelpers::Call call = jit.call(OperationPtrTag);
+
+    jit.jump(GPRInfo::returnValueGPR, ExceptionHandlerPtrTag);
+    jit.breakpoint(); // We should not reach this.
+
+    jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+        linkBuffer.link(call, FunctionPtr<OperationPtrTag>(Wasm::wasmToJSException));
+    });
+}
+
 } } // namespace JSC::Wasm
 
 #endif // ENABLE(WEBASSEMBLY)

Modified: trunk/Source/_javascript_Core/wasm/js/WasmToJS.h (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/WasmToJS.h	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/WasmToJS.h	2019-06-17 18:44:18 UTC (rev 246504)
@@ -45,6 +45,7 @@
 Expected<MacroAssemblerCodeRef<WasmEntryPtrTag>, BindingFailure> wasmToJS(VM*, Bag<CallLinkInfo>& callLinkInfos, SignatureIndex, unsigned importIndex);
 
 void* wasmToJSException(ExecState*, Wasm::ExceptionType, Instance*);
+void emitThrowWasmToJSException(CCallHelpers&, GPRReg wasmInstance, Wasm::ExceptionType);
 
 } } // namespace JSC::Wasm
 

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -84,6 +84,11 @@
         case Wasm::I32:
             arg = JSValue::decode(arg.toInt32(exec));
             break;
+        case Wasm::Anyfunc: {
+            if (!isWebAssemblyHostFunction(vm, arg) && !arg.isNull())
+                return JSValue::encode(throwException(exec, scope, createJSWebAssemblyRuntimeError(exec, vm, "Anyfunc must be an exported wasm function")));
+            break;
+        }
         case Wasm::Anyref:
             break;
         case Wasm::I64:
@@ -97,7 +102,6 @@
             break;
         case Wasm::Void:
         case Wasm::Func:
-        case Wasm::Anyfunc:
             RELEASE_ASSERT_NOT_REACHED();
         }
         RETURN_IF_EXCEPTION(scope, encodedJSValue());
@@ -228,6 +232,7 @@
             argumentsIncludeI64 = true;
             break;
         case Wasm::Anyref:
+        case Wasm::Anyfunc:
         case Wasm::I32:
             if (numGPRs >= Wasm::wasmCallingConvention().m_gprArgs.size())
                 totalFrameSize += sizeof(CPURegister);
@@ -303,6 +308,27 @@
                     ++numGPRs;
                 }
                 break;
+            case Wasm::Anyfunc: {
+                // FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
+                bool (*shouldThrow)(Wasm::Instance*, JSValue) = [] (Wasm::Instance* wasmInstance, JSValue arg) -> bool {
+                    JSWebAssemblyInstance* instance = wasmInstance->owner<JSWebAssemblyInstance>();
+                    JSGlobalObject* globalObject = instance->globalObject();
+                    VM& vm = globalObject->vm();
+                    return !isWebAssemblyHostFunction(vm, arg) && !arg.isNull();
+                };
+                jit.move(CCallHelpers::TrustedImmPtr(&instance()->instance()), GPRInfo::argumentGPR0);
+                jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), GPRInfo::argumentGPR1);
+                jit.setupArguments<decltype(shouldThrow)>(GPRInfo::argumentGPR0, GPRInfo::argumentGPR1);
+                auto call = jit.call(OperationPtrTag);
+
+                jit.addLinkTask([=] (LinkBuffer& linkBuffer) {
+                    linkBuffer.link(call, FunctionPtr<OperationPtrTag>(shouldThrow));
+                });
+
+                slowPath.append(jit.branchTest32(CCallHelpers::NonZero, GPRInfo::returnValueGPR));
+
+                FALLTHROUGH;
+            }
             case Wasm::Anyref: {
                 jit.load64(CCallHelpers::Address(GPRInfo::callFrameRegister, jsOffset), scratchGPR);
 
@@ -466,13 +492,11 @@
         isNaN.link(&jit);
         break;
     }
-    case Wasm::Anyref: {
-        // FIXME: We need to box wasm Funcrefs once they are supported here.
+    case Wasm::Anyfunc:
+    case Wasm::Anyref:
         break;
-    }
     case Wasm::I64:
     case Wasm::Func:
-    case Wasm::Anyfunc:
         return nullptr;
     default:
         break;

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2019-06-17 18:44:18 UTC (rev 246504)
@@ -235,10 +235,15 @@
             // ii. If the global_type of i is i64 or Type(v) is not Number, throw a WebAssembly.LinkError.
             if (moduleInformation.globals[import.kindIndex].type == Wasm::I64)
                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "cannot be an i64")));
-            if (moduleInformation.globals[import.kindIndex].type != Wasm::Anyref && !value.isNumber())
+            if (!isSubtype(moduleInformation.globals[import.kindIndex].type, Wasm::Anyref) && !value.isNumber())
                 return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a number")));
             // iii. Append ToWebAssemblyValue(v) to imports.
             switch (moduleInformation.globals[import.kindIndex].type) {
+            case Wasm::Anyfunc:
+                if (!isWebAssemblyHostFunction(vm, value) && !value.isNull())
+                    return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "imported global", "must be a wasm exported function or null")));
+                m_instance->instance().setGlobal(import.kindIndex, value);
+                break;
             case Wasm::Anyref:
                 m_instance->instance().setGlobal(import.kindIndex, value);
                 break;
@@ -319,6 +324,47 @@
         }
     }
 
+    unsigned functionImportCount = codeBlock->functionImportCount();
+    auto makeFunctionWrapper = [&] (const String& field, uint32_t index) -> JSValue {
+        // If we already made a wrapper, do not make a new one.
+        JSValue wrapper = m_instance->instance().getFunctionWrapper(index);
+
+        if (!wrapper.isNull())
+            return wrapper;
+
+        // 1. If e is a closure c:
+        //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
+        //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
+        if (index < functionImportCount) {
+            JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(index)->get();
+            if (isWebAssemblyHostFunction(vm, functionImport))
+                wrapper = functionImport;
+            else {
+                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(index);
+                wrapper = WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, index, m_instance.get(), signatureIndex);
+            }
+        } else {
+            //   iii. Otherwise:
+            //     a. Let func be an Exported Function Exotic Object created from c.
+            //     b. Append func to funcs.
+            //     c. Return func.
+            Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(index);
+            Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(index);
+            Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(index);
+            const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
+            WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), field, m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
+            wrapper = function;
+        }
+
+        ASSERT(wrapper.isFunction(vm));
+        m_instance->instance().setFunctionWrapper(index, wrapper);
+
+        return wrapper;
+    };
+
+    for (auto index : moduleInformation.referencedFunctions())
+        makeFunctionWrapper("Referenced function", index);
+
     // Globals
     {
         for (size_t globalIndex = moduleInformation.firstInternalGlobal; globalIndex < moduleInformation.globals.size(); ++globalIndex) {
@@ -327,6 +373,10 @@
             if (global.initializationType == Wasm::Global::FromGlobalImport) {
                 ASSERT(global.initialBitsOrImportNumber < moduleInformation.firstInternalGlobal);
                 m_instance->instance().setGlobal(globalIndex, m_instance->instance().loadI64Global(global.initialBitsOrImportNumber));
+            } else if (global.initializationType == Wasm::Global::FromRefFunc) {
+                ASSERT(global.initialBitsOrImportNumber < moduleInformation.functionIndexSpaceSize());
+                ASSERT(makeFunctionWrapper("Global init expr", global.initialBitsOrImportNumber).isFunction(vm));
+                m_instance->instance().setGlobal(globalIndex, JSValue::encode(makeFunctionWrapper("Global init expr", global.initialBitsOrImportNumber)));
             } else
                 m_instance->instance().setGlobal(globalIndex, global.initialBitsOrImportNumber);
         }
@@ -333,7 +383,6 @@
     }
 
     SymbolTable* exportSymbolTable = module->exportSymbolTable();
-    unsigned functionImportCount = codeBlock->functionImportCount();
 
     // Let exports be a list of (string, JS value) pairs that is mapped from each external value e in instance.exports as follows:
     JSModuleEnvironment* moduleEnvironment = JSModuleEnvironment::create(vm, globalObject, nullptr, exportSymbolTable, JSValue(), this);
@@ -341,30 +390,9 @@
         JSValue exportedValue;
         switch (exp.kind) {
         case Wasm::ExternalKind::Function: {
-            // 1. If e is a closure c:
-            //   i. If there is an Exported Function Exotic Object func in funcs whose func.[[Closure]] equals c, then return func.
-            //   ii. (Note: At most one wrapper is created for any closure, so func is unique, even if there are multiple occurrances in the list. Moreover, if the item was an import that is already an Exported Function Exotic Object, then the original function object will be found. For imports that are regular JS functions, a new wrapper will be created.)
-            if (exp.kindIndex < functionImportCount) {
-                unsigned functionIndex = exp.kindIndex;
-                JSObject* functionImport = m_instance->instance().importFunction<WriteBarrier<JSObject>>(functionIndex)->get();
-                if (isWebAssemblyHostFunction(vm, functionImport))
-                    exportedValue = functionImport;
-                else {
-                    Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(functionIndex);
-                    exportedValue = WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex);
-                }
-            } else {
-                //   iii. Otherwise:
-                //     a. Let func be an Exported Function Exotic Object created from c.
-                //     b. Append func to funcs.
-                //     c. Return func.
-                Wasm::Callee& embedderEntrypointCallee = codeBlock->embedderEntrypointCalleeFromFunctionIndexSpace(exp.kindIndex);
-                Wasm::WasmToWasmImportableFunction::LoadLocation entrypointLoadLocation = codeBlock->entrypointLoadLocationFromFunctionIndexSpace(exp.kindIndex);
-                Wasm::SignatureIndex signatureIndex = module->signatureIndexFromFunctionIndexSpace(exp.kindIndex);
-                const Wasm::Signature& signature = Wasm::SignatureInformation::get(signatureIndex);
-                WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String::fromUTF8(exp.field), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
-                exportedValue = function;
-            }
+            exportedValue = makeFunctionWrapper(String::fromUTF8(exp.field), exp.kindIndex);
+            ASSERT(exportedValue.isFunction(vm));
+            ASSERT(makeFunctionWrapper(String::fromUTF8(exp.field), exp.kindIndex) == exportedValue);
             break;
         }
         case Wasm::ExternalKind::Table: {
@@ -388,8 +416,7 @@
             // Return ToJSValue(v).
             switch (global.type) {
             case Wasm::Anyref:
-                // FIXME: We need to box wasm Funcrefs once they are supported here.
-                // <https://bugs.webkit.org/show_bug.cgi?id=198157>
+            case Wasm::Anyfunc:
                 exportedValue = JSValue::decode(m_instance->instance().loadI64Global(exp.kindIndex));
                 break;
 

Modified: trunk/Source/_javascript_Core/wasm/wasm.json (246503 => 246504)


--- trunk/Source/_javascript_Core/wasm/wasm.json	2019-06-17 18:29:30 UTC (rev 246503)
+++ trunk/Source/_javascript_Core/wasm/wasm.json	2019-06-17 18:44:18 UTC (rev 246504)
@@ -11,13 +11,13 @@
         "i64":     { "type": "varint7", "value":  -2, "b3type": "B3::Int64" },
         "f32":     { "type": "varint7", "value":  -3, "b3type": "B3::Float" },
         "f64":     { "type": "varint7", "value":  -4, "b3type": "B3::Double" },
-        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Void" },
+        "anyfunc": { "type": "varint7", "value": -16, "b3type": "B3::Int64" },
         "anyref":  { "type": "varint7", "value": -17, "b3type": "B3::Int64" },
         "func":    { "type": "varint7", "value": -32, "b3type": "B3::Void" },
         "void":    { "type": "varint7", "value": -64, "b3type": "B3::Void" }
     },
-    "value_type": ["i32", "i64", "f32", "f64", "anyref"],
-    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
+    "value_type": ["i32", "i64", "f32", "f64", "anyref", "anyfunc"],
+    "block_type": ["i32", "i64", "f32", "f64", "void", "anyref", "anyfunc"],
     "elem_type": ["anyfunc","anyref"],
     "external_kind": {
         "Function": { "type": "uint8", "value": 0 },
@@ -59,8 +59,9 @@
         "i64.const":           { "category": "special",    "value":  66, "return": ["i64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "varint64"}],                                             "description": "a constant value interpreted as i64" },
         "f64.const":           { "category": "special",    "value":  68, "return": ["f64"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "double"}],                                               "description": "a constant value interpreted as f64" },
         "f32.const":           { "category": "special",    "value":  67, "return": ["f32"],      "parameter": [],                       "immediate": [{"name": "value",          "type": "float"}],                                                "description": "a constant value interpreted as f32" },
-        "ref.null":            { "category": "special",    "value": 208, "return": ["anyref"],   "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
+        "ref.null":            { "category": "special",    "value": 208, "return": ["anyfunc"],  "parameter": [],                       "immediate": [],                                                                                           "description": "a constant null reference" },
         "ref.is_null":         { "category": "special",    "value": 209, "return": ["i32"],      "parameter": ["anyref"],               "immediate": [],                                                                                           "description": "determine if a reference is null" },
+        "ref.func":            { "category": "special",    "value": 210, "return": ["anyfunc"],  "parameter": [],                       "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "return a reference to the function at the given index" },
         "get_local":           { "category": "special",    "value":  32, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "read a local variable or parameter" },
         "set_local":           { "category": "special",    "value":  33, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter" },
         "tee_local":           { "category": "special",    "value":  34, "return": ["any"],      "parameter": ["any"],                  "immediate": [{"name": "local_index",    "type": "varuint32"}],                                            "description": "write a local variable or parameter and return the same value" },
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to