Title: [246139] trunk
Revision
246139
Author
justin_mich...@apple.com
Date
2019-06-05 20:14:47 -0700 (Wed, 05 Jun 2019)

Log Message

[WASM-References] Add support for Anyref tables, Table.get and Table.set (for Anyref only).
https://bugs.webkit.org/show_bug.cgi?id=198398

Reviewed by Saam Barati.

JSTests:

* wasm/references/anyref_table.js: Added.
(string_appeared_here.doGCSet):
(doGCTest):
(doGCSet.doGCTest.let.count.0.doBarrierSet):
* wasm/references/anyref_table_import.js: Added.
(makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
(string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
* wasm/references/is_null_error.js: Removed.
* wasm/references/validation.js: Added.
(assert.throws.new.WebAssembly.Module.bin):
(assert.throws):
* wasm/wasm.json:

Source/_javascript_Core:

Create a new table subtype called FuncRefTable (note: Anyfunc was renamed to Funcref in the references spec).
Table now write-barriers and visits its children's wrapper objects. FuncRefTable caches some extra data to
support calling from wasm. A JSWebAssemblyTable is required to set an anyref element, but this is only because
we need to write barrier it (so it should not restrict how we implement threads). This patch does, however,
restrict the implementation of function references to require every Ref.func to have an associated wrapper. This
can be done statically, so this too should not restrict our threads implementation.

* wasm/WasmAirIRGenerator.cpp:
(JSC::Wasm::AirIRGenerator::addTableGet):
(JSC::Wasm::AirIRGenerator::addTableSet):
(JSC::Wasm::AirIRGenerator::addCallIndirect):
* wasm/WasmB3IRGenerator.cpp:
(JSC::Wasm::B3IRGenerator::addLocal):
(JSC::Wasm::B3IRGenerator::addTableGet):
(JSC::Wasm::B3IRGenerator::addTableSet):
(JSC::Wasm::B3IRGenerator::addCallIndirect):
* wasm/WasmFormat.h:
(JSC::Wasm::TableInformation::TableInformation):
(JSC::Wasm::TableInformation::type const):
* wasm/WasmFunctionParser.h:
(JSC::Wasm::FunctionParser<Context>::parseExpression):
(JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
* wasm/WasmSectionParser.cpp:
(JSC::Wasm::SectionParser::parseTableHelper):
* wasm/WasmTable.cpp:
(JSC::Wasm::Table::Table):
(JSC::Wasm::Table::tryCreate):
(JSC::Wasm::Table::grow):
(JSC::Wasm::Table::clear):
(JSC::Wasm::Table::set):
(JSC::Wasm::Table::get):
(JSC::Wasm::Table::visitChildren):
(JSC::Wasm::FuncRefTable::FuncRefTable):
(JSC::Wasm::FuncRefTable::setFunction):
(JSC::Wasm::Table::~Table): Deleted.
(JSC::Wasm::Table::clearFunction): Deleted.
(JSC::Wasm::Table::setFunction): Deleted.
* wasm/WasmTable.h:
(JSC::Wasm::Table::length const):
(JSC::Wasm::Table::type const):
(JSC::Wasm::Table::setOwner):
(JSC::Wasm::FuncRefTable::offsetOfFunctions):
(JSC::Wasm::FuncRefTable::offsetOfInstances):
(JSC::Wasm::Table::offsetOfFunctions): Deleted.
(JSC::Wasm::Table::offsetOfInstances): Deleted.
* wasm/WasmValidate.cpp:
(JSC::Wasm::Validate::addTableGet):
(JSC::Wasm::Validate::addTableSet):
(JSC::Wasm::Validate::addCallIndirect):
* wasm/js/JSWebAssemblyTable.cpp:
(JSC::JSWebAssemblyTable::JSWebAssemblyTable):
(JSC::JSWebAssemblyTable::finishCreation):
(JSC::JSWebAssemblyTable::visitChildren):
(JSC::JSWebAssemblyTable::grow):
(JSC::JSWebAssemblyTable::get):
(JSC::JSWebAssemblyTable::set):
(JSC::JSWebAssemblyTable::clear):
(JSC::JSWebAssemblyTable::getFunction): Deleted.
(JSC::JSWebAssemblyTable::clearFunction): Deleted.
(JSC::JSWebAssemblyTable::setFunction): Deleted.
* wasm/js/JSWebAssemblyTable.h:
* wasm/js/WebAssemblyModuleRecord.cpp:
(JSC::WebAssemblyModuleRecord::link):
(JSC::WebAssemblyModuleRecord::evaluate):
* wasm/js/WebAssemblyTableConstructor.cpp:
(JSC::constructJSWebAssemblyTable):
* wasm/js/WebAssemblyTablePrototype.cpp:
(JSC::webAssemblyTableProtoFuncGet):
(JSC::webAssemblyTableProtoFuncSet):
* wasm/wasm.json:

Modified Paths

Added Paths

Removed Paths

Diff

Modified: trunk/JSTests/ChangeLog (246138 => 246139)


--- trunk/JSTests/ChangeLog	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/JSTests/ChangeLog	2019-06-06 03:14:47 UTC (rev 246139)
@@ -1,5 +1,26 @@
 2019-06-05  Justin Michaud  <justin_mich...@apple.com>
 
+        [WASM-References] Add support for Anyref tables, Table.get and Table.set (for Anyref only).
+        https://bugs.webkit.org/show_bug.cgi?id=198398
+
+        Reviewed by Saam Barati.
+
+        * wasm/references/anyref_table.js: Added.
+        (string_appeared_here.doGCSet):
+        (doGCTest):
+        (doGCSet.doGCTest.let.count.0.doBarrierSet):
+        * wasm/references/anyref_table_import.js: Added.
+        (makeImport):
+        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
+        (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
+        * wasm/references/is_null_error.js: Removed.
+        * wasm/references/validation.js: Added.
+        (assert.throws.new.WebAssembly.Module.bin):
+        (assert.throws):
+        * wasm/wasm.json:
+
+2019-06-05  Justin Michaud  <justin_mich...@apple.com>
+
         WebAssembly: pow functions returns 0 when exponent 1.0 or -1.0
         https://bugs.webkit.org/show_bug.cgi?id=198106
 

Modified: trunk/JSTests/wasm/js-api/table.js (246138 => 246139)


--- trunk/JSTests/wasm/js-api/table.js	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/JSTests/wasm/js-api/table.js	2019-06-06 03:14:47 UTC (rev 246139)
@@ -132,29 +132,29 @@
 {
     let badDescriptions = [
         [{initial: 10, element: "i32"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, element: "f32"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, element: "f64"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, element: "i64"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, maximum: 20, element: "i32"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -1 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, maximum: 20, element: "f32"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -3 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, maximum: 20, element: "f64"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -4 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
         [{initial: 10, maximum: 20, element: "i64"},
-         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
-         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
+         "WebAssembly.Module doesn't parse at byte 18: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",
+         "WebAssembly.Module doesn't parse at byte 26: Table type should be anyfunc or anyref, got -2 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')"],
 
         [{initial: 10, maximum: 9, element: "anyfunc"},
          "WebAssembly.Module doesn't parse at byte 21: resizable limits has a initial page count of 10 which is greater than its maximum 9 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')",

Added: trunk/JSTests/wasm/references/anyref_table.js (0 => 246139)


--- trunk/JSTests/wasm/references/anyref_table.js	                        (rev 0)
+++ trunk/JSTests/wasm/references/anyref_table.js	2019-06-06 03:14:47 UTC (rev 246139)
@@ -0,0 +1,100 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Function().End()
+      .Table()
+            .Table({initial: 20, maximum: 30, element: "anyref"})
+      .End()
+      .Export()
+          .Function("set_tbl")
+          .Function("get_tbl")
+          .Function("tbl_is_null")
+          .Function("set_tbl_null")
+          .Table("tbl", 0)
+      .End()
+      .Code()
+        .Function("set_tbl", { params: ["anyref"], ret: "void" })
+          .I32Const(0)
+          .GetLocal(0)
+          .TableSet()
+        .End()
+
+        .Function("get_tbl", { params: [], ret: "anyref" })
+          .I32Const(0)
+          .TableGet()
+        .End()
+
+        .Function("tbl_is_null", { params: [], ret: "i32" })
+            .Call(1)
+            .RefIsNull()
+        .End()
+
+        .Function("set_tbl_null", { params: [], ret: "void" })
+            .RefNull()
+            .Call(0)
+        .End()
+      .End().WebAssembly().get()));
+
+fullGC()
+
+assert.eq($1.exports.get_tbl(), null)
+assert.eq($1.exports.tbl_is_null(), 1)
+
+$1.exports.set_tbl("hi")
+fullGC()
+assert.eq($1.exports.get_tbl(), "hi")
+assert.eq($1.exports.tbl_is_null(), 0)
+
+assert.eq($1.exports.tbl.get(0), "hi")
+assert.eq($1.exports.tbl.get(1), null)
+
+$1.exports.tbl.set(0, { test: "test" });
+fullGC()
+assert.eq($1.exports.get_tbl().test, "test")
+
+assert.eq($1.exports.tbl.grow(10), 20)
+assert.eq($1.exports.tbl.grow(0), 30)
+assert.eq($1.exports.get_tbl().test, "test")
+fullGC()
+assert.eq($1.exports.get_tbl().test, "test")
+
+function doGCSet() {
+    fullGC()
+    $1.exports.set_tbl({ test: -1 })
+    fullGC()
+}
+
+function doGCTest() {
+    for (let i=0; i<1000; ++i) {
+        assert.eq($1.exports.get_tbl().test, -1)
+        fullGC()
+    }
+}
+
+doGCSet()
+doGCTest()
+
+let count = 0
+
+function doBarrierSet() {
+    ++count
+    $1.exports.set_tbl({ test: -count })
+}
+
+function doBarrierTest() {
+    let garbage = { val: "hi", val2: 5, arr: [] }
+    for (let i=0; i<100; ++i) garbage.arr += ({ field: i })
+
+    for (let j=0; j<1000; ++j) {
+        assert.eq($1.exports.get_tbl().test, -count)
+        edenGC()
+    }
+}
+
+for (let i=0; i<5; ++i) {
+    doBarrierSet()
+    doBarrierTest()
+    doBarrierTest()
+}

Added: trunk/JSTests/wasm/references/anyref_table_import.js (0 => 246139)


--- trunk/JSTests/wasm/references/anyref_table_import.js	                        (rev 0)
+++ trunk/JSTests/wasm/references/anyref_table_import.js	2019-06-06 03:14:47 UTC (rev 246139)
@@ -0,0 +1,227 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+{
+    function makeImport() {
+        const tbl = new WebAssembly.Table({initial:2, element:"anyref"});
+
+        const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+          .Type().End()
+          .Import()
+                .Table("imp", "tbl", {initial: 2, element: "anyref"})
+          .End()
+          .Function().End()
+          .Export()
+              .Function("set_tbl")
+              .Function("get_tbl")
+              .Function("tbl_is_null")
+              .Function("set_tbl_null")
+              .Table("tbl", 0)
+          .End()
+          .Code()
+            .Function("set_tbl", { params: ["anyref"], ret: "void" })
+              .I32Const(0)
+              .GetLocal(0)
+              .TableSet()
+            .End()
+
+            .Function("get_tbl", { params: [], ret: "anyref" })
+              .I32Const(0)
+              .TableGet()
+            .End()
+
+            .Function("tbl_is_null", { params: [], ret: "i32" })
+                .Call(1)
+                .RefIsNull()
+            .End()
+
+            .Function("set_tbl_null", { params: [], ret: "void" })
+                .RefNull()
+                .Call(0)
+            .End()
+          .End().WebAssembly().get()), { imp: { tbl }});
+        fullGC()
+        return $1
+    }
+
+    const $1 = makeImport()
+    fullGC()
+
+    assert.eq($1.exports.get_tbl(), null)
+    assert.eq($1.exports.tbl_is_null(), 1)
+
+    $1.exports.set_tbl("hi")
+    fullGC()
+    assert.eq($1.exports.get_tbl(), "hi")
+    assert.eq($1.exports.tbl_is_null(), 0)
+
+    assert.eq($1.exports.tbl.get(0), "hi")
+    assert.eq($1.exports.tbl.get(1), null)
+
+    $1.exports.tbl.set(0, { test: "test" });
+    fullGC()
+    assert.eq($1.exports.get_tbl().test, "test")
+
+    assert.eq($1.exports.tbl.grow(10), 2)
+    assert.eq($1.exports.tbl.grow(0), 12)
+    assert.eq($1.exports.get_tbl().test, "test")
+    fullGC()
+    assert.eq($1.exports.get_tbl().test, "test")
+}
+
+{
+    function makeImport() {
+        const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+          .Type().End()
+          .Import()
+                .Table("imp", "tbl", {initial: 2, element: "anyref"})
+          .End()
+          .Function().End()
+          .Export()
+              .Function("set_tbl")
+              .Function("get_tbl")
+              .Function("tbl_is_null")
+              .Function("set_tbl_null")
+              .Table("tbl", 0)
+          .End()
+          .Code()
+            .Function("set_tbl", { params: ["anyref"], ret: "void" })
+              .I32Const(0)
+              .GetLocal(0)
+              .TableSet()
+            .End()
+
+            .Function("get_tbl", { params: [], ret: "anyref" })
+              .I32Const(0)
+              .TableGet()
+            .End()
+
+            .Function("tbl_is_null", { params: [], ret: "i32" })
+                .Call(1)
+                .RefIsNull()
+            .End()
+
+            .Function("set_tbl_null", { params: [], ret: "void" })
+                .RefNull()
+                .Call(0)
+            .End()
+          .End().WebAssembly().get()), { imp: { tbl: new WebAssembly.Table({initial:2, element:"anyref"}) }});
+        fullGC()
+
+        $1.exports.tbl.set(0, { test: "test" });
+
+        const $2 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+          .Type().End()
+          .Import()
+                .Table("imp", "tbl", {initial: 2, element: "anyref"})
+          .End()
+          .Function().End()
+          .Export()
+              .Function("set_tbl")
+              .Function("get_tbl")
+              .Function("tbl_is_null")
+              .Function("set_tbl_null")
+              .Table("tbl", 0)
+          .End()
+          .Code()
+            .Function("set_tbl", { params: ["anyref"], ret: "void" })
+              .I32Const(0)
+              .GetLocal(0)
+              .TableSet()
+            .End()
+
+            .Function("get_tbl", { params: [], ret: "anyref" })
+              .I32Const(0)
+              .TableGet()
+            .End()
+
+            .Function("tbl_is_null", { params: [], ret: "i32" })
+                .Call(1)
+                .RefIsNull()
+            .End()
+
+            .Function("set_tbl_null", { params: [], ret: "void" })
+                .RefNull()
+                .Call(0)
+            .End()
+          .End().WebAssembly().get()), { imp: { tbl: $1.exports.tbl }});
+        fullGC()
+
+        return $2
+    }
+
+    const $1 = makeImport()
+    fullGC()
+
+    assert.eq($1.exports.get_tbl().test, "test")
+    assert.eq($1.exports.tbl_is_null(), 0)
+
+    $1.exports.set_tbl("hi")
+    fullGC()
+    assert.eq($1.exports.get_tbl(), "hi")
+    assert.eq($1.exports.tbl_is_null(), 0)
+
+    assert.eq($1.exports.tbl.get(0), "hi")
+    assert.eq($1.exports.tbl.get(1), null)
+
+    $1.exports.tbl.set(0, { test: "test" });
+    fullGC()
+    assert.eq($1.exports.get_tbl().test, "test")
+
+    assert.eq($1.exports.tbl.grow(10), 2)
+    assert.eq($1.exports.tbl.grow(0), 12)
+    assert.eq($1.exports.get_tbl().test, "test")
+    fullGC()
+    assert.eq($1.exports.get_tbl().test, "test")
+}
+
+{
+    let tbl = new WebAssembly.Table({initial:1, element:"anyref"});
+
+    function doSet(i, v) {
+        tbl.set(i, { test: v });
+    }
+
+    function makeGarbage(depth) {
+        let garbage = { val: "hi", val2: 5, arr: [] }
+        for (let i=0; i<100; ++i) garbage.arr += ({ field: i })
+
+        if (depth < 5)
+            return 1 + makeGarbage(depth + 1);
+        return 0;
+    }
+
+    for (let iter=0; iter<5; ++iter) {
+        for (let k=0; k<100; ++k)
+            tbl = new WebAssembly.Table({initial:100, element:"anyref"})
+
+        for (let i=1; i<20; ++i) {
+            const len = tbl.length;
+            for (let j=0; j<len; ++j)
+                doSet(j, j);
+            makeGarbage(0);
+            tbl.grow(Math.pow(2,i));
+            for (let j=0; j<len; ++j)
+                assert.eq(tbl.get(j).test, j);
+            for (let j=0; j<tbl.length; ++j)
+                doSet(j, -j);
+        }
+    }
+}
+
+{
+    const tbl = new WebAssembly.Table({initial:2, element:"anyfunc"});
+
+    const mod = new WebAssembly.Module((new Builder())
+      .Type().End()
+      .Import()
+            .Table("imp", "tbl", {initial: 2, element: "anyref"})
+      .End()
+      .Function().End()
+      .Export()
+      .End()
+      .Code()
+      .End().WebAssembly().get())
+
+    assert.throws(() => new WebAssembly.Instance(mod, { imp: { tbl }}), Error, "Table import imp:tbl provided a 'type' that is wrong (evaluating 'new WebAssembly.Instance(mod, { imp: { tbl }})')");
+}

Deleted: trunk/JSTests/wasm/references/is_null_error.js (246138 => 246139)


--- trunk/JSTests/wasm/references/is_null_error.js	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/JSTests/wasm/references/is_null_error.js	2019-06-06 03:14:47 UTC (rev 246139)
@@ -1,22 +0,0 @@
-import * as assert from '../assert.js';
-import Builder from '../Builder.js';
-
-{
-    const builder = (new Builder())
-      .Type().End()
-      .Function().End()
-      .Export()
-          .Function("j")
-      .End()
-      .Code()
-        .Function("j", { params: [], ret: "i32" })
-            .I32Const(0)
-            .RefIsNull()
-        .End()
-      .End();
-
-    const bin = builder.WebAssembly();
-    bin.trim();
-
-    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: ref.is_null to type I32 expected Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
-}

Added: trunk/JSTests/wasm/references/validation.js (0 => 246139)


--- trunk/JSTests/wasm/references/validation.js	                        (rev 0)
+++ trunk/JSTests/wasm/references/validation.js	2019-06-06 03:14:47 UTC (rev 246139)
@@ -0,0 +1,94 @@
+import * as assert from '../assert.js';
+import Builder from '../Builder.js';
+
+{
+    const builder = (new Builder())
+      .Type().End()
+      .Function().End()
+      .Export()
+          .Function("j")
+      .End()
+      .Code()
+        .Function("j", { params: [], ret: "i32" })
+            .I32Const(0)
+            .RefIsNull()
+        .End()
+      .End();
+
+    const bin = builder.WebAssembly();
+    bin.trim();
+
+    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: ref.is_null to type I32 expected Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
+}
+
+{
+    const builder = (new Builder())
+      .Type().End()
+      .Function().End()
+      .Export()
+          .Function("j")
+      .End()
+      .Code()
+        .Function("j", { params: [], ret: "void" })
+            .I32Const(0)
+            .I32Const(0)
+            .TableSet()
+        .End()
+      .End();
+
+    const bin = builder.WebAssembly();
+    bin.trim();
+
+    assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyref, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
+}
+
+{
+    const builder = (new Builder())
+      .Type().End()
+      .Import()
+            .Table("imp", "tbl", {initial: 2, element: "anyfunc"})
+      .End()
+      .Function().End()
+      .Export()
+          .Function("j")
+      .End()
+      .Code()
+        .Function("j", { params: ["anyref"], ret: "void" })
+            .I32Const(0)
+            .GetLocal(0)
+            .TableSet()
+        .End()
+      .End();
+
+    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())')");
+}
+
+{
+    const builder = (new Builder())
+      .Type().End()
+      .Import()
+            .Table("imp", "tbl", {initial: 2, element: "anyfunc"})
+      .End()
+      .Function().End()
+      .Export()
+          .Function("j")
+      .End()
+      .Code()
+        .Function("j", { params: [], ret: "anyref" })
+            .I32Const(0)
+            .TableGet()
+        .End()
+      .End();
+
+    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.Table({initial:2, element:"i32"}), TypeError, "WebAssembly.Table expects its 'element' field to be the string 'anyfunc' or 'anyref'");
+}

Modified: trunk/JSTests/wasm/wasm.json (246138 => 246139)


--- trunk/JSTests/wasm/wasm.json	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/JSTests/wasm/wasm.json	2019-06-06 03:14:47 UTC (rev 246139)
@@ -18,7 +18,7 @@
     },
     "value_type": ["i32", "i64", "f32", "f64", "anyref"],
     "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
-    "elem_type": ["anyfunc"],
+    "elem_type": ["anyfunc","anyref"],
     "external_kind": {
         "Function": { "type": "uint8", "value": 0 },
         "Table":    { "type": "uint8", "value": 1 },
@@ -66,6 +66,8 @@
         "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" },
         "get_global":          { "category": "special",    "value":  35, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "read a global variable" },
         "set_global":          { "category": "special",    "value":  36, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "write a global variable" },
+        "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [],                                                                                           "description": "get a table value" },
+        "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [],                                                                                           "description": "set a table value" },
         "call":                { "category": "call",       "value":  16, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "call a function by its index" },
         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "reserved", "type": "varuint1"}],  "description": "call a function indirect with an expected signature" },
         "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },

Modified: trunk/Source/_javascript_Core/ChangeLog (246138 => 246139)


--- trunk/Source/_javascript_Core/ChangeLog	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/ChangeLog	2019-06-06 03:14:47 UTC (rev 246139)
@@ -1,5 +1,83 @@
 2019-06-05  Justin Michaud  <justin_mich...@apple.com>
 
+        [WASM-References] Add support for Anyref tables, Table.get and Table.set (for Anyref only).
+        https://bugs.webkit.org/show_bug.cgi?id=198398
+
+        Reviewed by Saam Barati.
+
+        Create a new table subtype called FuncRefTable (note: Anyfunc was renamed to Funcref in the references spec).
+        Table now write-barriers and visits its children's wrapper objects. FuncRefTable caches some extra data to
+        support calling from wasm. A JSWebAssemblyTable is required to set an anyref element, but this is only because
+        we need to write barrier it (so it should not restrict how we implement threads). This patch does, however,
+        restrict the implementation of function references to require every Ref.func to have an associated wrapper. This
+        can be done statically, so this too should not restrict our threads implementation. 
+
+        * wasm/WasmAirIRGenerator.cpp:
+        (JSC::Wasm::AirIRGenerator::addTableGet):
+        (JSC::Wasm::AirIRGenerator::addTableSet):
+        (JSC::Wasm::AirIRGenerator::addCallIndirect):
+        * wasm/WasmB3IRGenerator.cpp:
+        (JSC::Wasm::B3IRGenerator::addLocal):
+        (JSC::Wasm::B3IRGenerator::addTableGet):
+        (JSC::Wasm::B3IRGenerator::addTableSet):
+        (JSC::Wasm::B3IRGenerator::addCallIndirect):
+        * wasm/WasmFormat.h:
+        (JSC::Wasm::TableInformation::TableInformation):
+        (JSC::Wasm::TableInformation::type const):
+        * wasm/WasmFunctionParser.h:
+        (JSC::Wasm::FunctionParser<Context>::parseExpression):
+        (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+        * wasm/WasmSectionParser.cpp:
+        (JSC::Wasm::SectionParser::parseTableHelper):
+        * wasm/WasmTable.cpp:
+        (JSC::Wasm::Table::Table):
+        (JSC::Wasm::Table::tryCreate):
+        (JSC::Wasm::Table::grow):
+        (JSC::Wasm::Table::clear):
+        (JSC::Wasm::Table::set):
+        (JSC::Wasm::Table::get):
+        (JSC::Wasm::Table::visitChildren):
+        (JSC::Wasm::FuncRefTable::FuncRefTable):
+        (JSC::Wasm::FuncRefTable::setFunction):
+        (JSC::Wasm::Table::~Table): Deleted.
+        (JSC::Wasm::Table::clearFunction): Deleted.
+        (JSC::Wasm::Table::setFunction): Deleted.
+        * wasm/WasmTable.h:
+        (JSC::Wasm::Table::length const):
+        (JSC::Wasm::Table::type const):
+        (JSC::Wasm::Table::setOwner):
+        (JSC::Wasm::FuncRefTable::offsetOfFunctions):
+        (JSC::Wasm::FuncRefTable::offsetOfInstances):
+        (JSC::Wasm::Table::offsetOfFunctions): Deleted.
+        (JSC::Wasm::Table::offsetOfInstances): Deleted.
+        * wasm/WasmValidate.cpp:
+        (JSC::Wasm::Validate::addTableGet):
+        (JSC::Wasm::Validate::addTableSet):
+        (JSC::Wasm::Validate::addCallIndirect):
+        * wasm/js/JSWebAssemblyTable.cpp:
+        (JSC::JSWebAssemblyTable::JSWebAssemblyTable):
+        (JSC::JSWebAssemblyTable::finishCreation):
+        (JSC::JSWebAssemblyTable::visitChildren):
+        (JSC::JSWebAssemblyTable::grow):
+        (JSC::JSWebAssemblyTable::get):
+        (JSC::JSWebAssemblyTable::set):
+        (JSC::JSWebAssemblyTable::clear):
+        (JSC::JSWebAssemblyTable::getFunction): Deleted.
+        (JSC::JSWebAssemblyTable::clearFunction): Deleted.
+        (JSC::JSWebAssemblyTable::setFunction): Deleted.
+        * wasm/js/JSWebAssemblyTable.h:
+        * wasm/js/WebAssemblyModuleRecord.cpp:
+        (JSC::WebAssemblyModuleRecord::link):
+        (JSC::WebAssemblyModuleRecord::evaluate):
+        * wasm/js/WebAssemblyTableConstructor.cpp:
+        (JSC::constructJSWebAssemblyTable):
+        * wasm/js/WebAssemblyTablePrototype.cpp:
+        (JSC::webAssemblyTableProtoFuncGet):
+        (JSC::webAssemblyTableProtoFuncSet):
+        * wasm/wasm.json:
+
+2019-06-05  Justin Michaud  <justin_mich...@apple.com>
+
         WebAssembly: pow functions returns 0 when exponent 1.0 or -1.0
         https://bugs.webkit.org/show_bug.cgi?id=198106
 

Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -232,8 +232,13 @@
     ExpressionType addConstant(Type, uint64_t);
     ExpressionType addConstant(BasicBlock*, Type, uint64_t);
 
+    // References
     PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
 
+    // Tables
+    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -949,6 +954,40 @@
     return { };
 }
 
+auto AirIRGenerator::addTableGet(ExpressionType& idx, 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::Anyref);
+
+    uint64_t (*doGet)(Instance*, int32_t) = [] (Instance* instance, int32_t idx) -> uint64_t {
+        return JSValue::encode(instance->table()->get(idx));
+    };
+
+    emitCCall(doGet, result, instanceValue(), idx);
+
+    return { };
+}
+
+auto AirIRGenerator::addTableSet(ExpressionType& idx, 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(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));
+    };
+
+    emitCCall(doSet, TypedTmp(), instanceValue(), idx, value);
+
+    return { };
+}
+
 auto AirIRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
 {
     ASSERT(m_locals[index].tmp());
@@ -1841,6 +1880,7 @@
 {
     ExpressionType calleeIndex = args.takeLast();
     ASSERT(signature.argumentCount() == args.size());
+    ASSERT(m_info.tableInformation.type() == TableElementType::Funcref);
 
     m_makesCalls = true;
     // Note: call indirect can call either WebAssemblyFunction or WebAssemblyWrapperFunction. Because
@@ -1856,13 +1896,13 @@
     ExpressionType callableFunctionBufferLength = g64();
     {
         RELEASE_ASSERT(Arg::isValidAddrForm(Instance::offsetOfTable(), B3::Width64));
-        RELEASE_ASSERT(Arg::isValidAddrForm(Table::offsetOfFunctions(), B3::Width64));
-        RELEASE_ASSERT(Arg::isValidAddrForm(Table::offsetOfInstances(), B3::Width64));
-        RELEASE_ASSERT(Arg::isValidAddrForm(Table::offsetOfLength(), B3::Width64));
+        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfFunctions(), B3::Width64));
+        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfInstances(), B3::Width64));
+        RELEASE_ASSERT(Arg::isValidAddrForm(FuncRefTable::offsetOfLength(), B3::Width64));
 
         append(Move, Arg::addr(instanceValue(), Instance::offsetOfTable()), callableFunctionBufferLength);
-        append(Move, Arg::addr(callableFunctionBufferLength, Table::offsetOfFunctions()), callableFunctionBuffer);
-        append(Move, Arg::addr(callableFunctionBufferLength, Table::offsetOfInstances()), instancesBuffer);
+        append(Move, Arg::addr(callableFunctionBufferLength, FuncRefTable::offsetOfFunctions()), callableFunctionBuffer);
+        append(Move, Arg::addr(callableFunctionBufferLength, FuncRefTable::offsetOfInstances()), instancesBuffer);
         append(Move32, Arg::addr(callableFunctionBufferLength, Table::offsetOfLength()), callableFunctionBufferLength);
     }
 

Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -185,8 +185,13 @@
     PartialResult WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type, uint64_t);
 
+    // References
     PartialResult WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
 
+    // Tables
+    PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
+    PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+
     // Locals
     PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     PartialResult WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -561,6 +566,36 @@
     return { };
 }
 
+auto B3IRGenerator::addTableGet(ExpressionType& idx, 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);
+
+    return { };
+}
+
+auto B3IRGenerator::addTableSet(ExpressionType& idx, 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));
+    };
+
+    m_currentBlock->appendNew<CCallValue>(m_proc, B3::Void, origin(),
+        m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(doSet, B3CCallPtrTag)),
+        instanceValue(), idx, value);
+
+    return { };
+}
+
 auto B3IRGenerator::getLocal(uint32_t index, ExpressionType& result) -> PartialResult
 {
     ASSERT(m_locals[index]);
@@ -1263,9 +1298,9 @@
         ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
             instanceValue(), safeCast<int32_t>(Instance::offsetOfTable()));
         callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            table, safeCast<int32_t>(Table::offsetOfFunctions()));
+            table, safeCast<int32_t>(FuncRefTable::offsetOfFunctions()));
         instancesBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
-            table, safeCast<int32_t>(Table::offsetOfInstances()));
+            table, safeCast<int32_t>(FuncRefTable::offsetOfInstances()));
         callableFunctionBufferLength = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, origin(),
             table, safeCast<int32_t>(Table::offsetOfLength()));
         mask = m_currentBlock->appendNew<Value>(m_proc, ZExt32, origin(),

Modified: trunk/Source/_javascript_Core/wasm/WasmFormat.h (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmFormat.h	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmFormat.h	2019-06-06 03:14:47 UTC (rev 246139)
@@ -54,6 +54,11 @@
 struct CompilationContext;
 struct ModuleInformation;
 
+enum class TableElementType : uint8_t {
+    Anyref,
+    Funcref
+};
+
 inline bool isValueType(Type type)
 {
     switch (type) {
@@ -214,11 +219,12 @@
         ASSERT(!*this);
     }
 
-    TableInformation(uint32_t initial, Optional<uint32_t> maximum, bool isImport)
+    TableInformation(uint32_t initial, Optional<uint32_t> maximum, bool isImport, TableElementType type)
         : m_initial(initial)
         , m_maximum(maximum)
         , m_isImport(isImport)
         , m_isValid(true)
+        , m_type(type)
     {
         ASSERT(*this);
     }
@@ -227,6 +233,7 @@
     bool isImport() const { return m_isImport; }
     uint32_t initial() const { return m_initial; }
     Optional<uint32_t> maximum() const { return m_maximum; }
+    TableElementType type() const { return m_type; }
 
 private:
     uint32_t m_initial;
@@ -233,6 +240,7 @@
     Optional<uint32_t> m_maximum;
     bool m_isImport { false };
     bool m_isValid { false };
+    TableElementType m_type;
 };
     
 struct CustomSection {

Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h	2019-06-06 03:14:47 UTC (rev 246139)
@@ -281,6 +281,24 @@
         return { };
     }
 
+    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));
+        m_expressionStack.append(result);
+        return { };
+    }
+
+    case TableSet: {
+        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+        ExpressionType val, idx;
+        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));
+        return { };
+    }
+
     case RefNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         m_expressionStack.append(m_context.addConstant(Anyref, JSValue::encode(jsNull())));
@@ -373,6 +391,7 @@
         WASM_PARSER_FAIL_IF(!parseVarUInt1(reserved), "can't get call_indirect's reserved byte");
         WASM_PARSER_FAIL_IF(reserved, "call_indirect's 'reserved' varuint1 must be 0x0");
         WASM_PARSER_FAIL_IF(m_info.usedSignatures.size() <= signatureIndex, "call_indirect's signature index ", signatureIndex, " exceeds known signatures ", m_info.usedSignatures.size());
+        WASM_PARSER_FAIL_IF(m_info.tableInformation.type() != TableElementType::Funcref, "call_indirect is only valid when a table has type anyfunc");
 
         const Signature& calleeSignature = m_info.usedSignatures[signatureIndex].get();
         size_t argumentCount = calleeSignature.argumentCount() + 1; // Add the callee's index.
@@ -654,16 +673,14 @@
         return { };
     }
 
+    case TableGet:
+    case TableSet:
+    case RefIsNull:
     case RefNull: {
         WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
         return { };
     }
 
-    case RefIsNull: {
-        WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
-        return { };
-    }
-
     case GrowMemory:
     case CurrentMemory: {
         uint8_t reserved;

Modified: trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -196,7 +196,7 @@
 
     int8_t type;
     WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type");
-    WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc, "Table type should be anyfunc, got ", type);
+    WASM_PARSER_FAIL_IF(type != Wasm::Anyfunc && type != Wasm::Anyref, "Table type should be anyfunc or anyref, got ", type);
 
     uint32_t initial;
     Optional<uint32_t> maximum;
@@ -207,7 +207,8 @@
 
     ASSERT(!maximum || *maximum >= initial);
 
-    m_info->tableInformation = TableInformation(initial, maximum, isImport);
+    TableElementType tableType = type == Wasm::Anyfunc ? TableElementType::Funcref : TableElementType::Anyref;
+    m_info->tableInformation = TableInformation(initial, maximum, isImport, tableType);
 
     return { };
 }

Modified: trunk/Source/_javascript_Core/wasm/WasmTable.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmTable.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmTable.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -47,40 +47,44 @@
     ASSERT(m_mask == WTF::maskForSize(allocatedLength(length)));
 }
 
-RefPtr<Table> Table::tryCreate(uint32_t initial, Optional<uint32_t> maximum)
+Table::Table(uint32_t initial, Optional<uint32_t> maximum, TableElementType type)
+    : m_type(type)
+    , m_maximum(maximum)
+    , m_owner(nullptr)
 {
-    if (!isValidLength(initial))
-        return nullptr;
-    return adoptRef(new (NotNull, fastMalloc(sizeof(Table))) Table(initial, maximum));
-}
-
-Table::~Table()
-{
-}
-
-Table::Table(uint32_t initial, Optional<uint32_t> maximum)
-{
     setLength(initial);
-    m_maximum = maximum;
     ASSERT(!m_maximum || *m_maximum >= m_length);
 
     // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
     // But for now, we're not doing that.
-    m_importableFunctions = MallocPtr<WasmToWasmImportableFunction>::malloc((sizeof(WasmToWasmImportableFunction) * Checked<size_t>(allocatedLength(m_length))).unsafeGet());
     // FIXME this over-allocates and could be smarter about not committing all of that memory https://bugs.webkit.org/show_bug.cgi?id=181425
-    m_instances = MallocPtr<Instance*>::malloc((sizeof(Instance*) * Checked<size_t>(allocatedLength(m_length))).unsafeGet());
+    m_jsValues = MallocPtr<WriteBarrier<Unknown>>::malloc((sizeof(WriteBarrier<Unknown>) * Checked<size_t>(allocatedLength(m_length))).unsafeGet());
     for (uint32_t i = 0; i < allocatedLength(m_length); ++i) {
-        new (&m_importableFunctions.get()[i]) WasmToWasmImportableFunction();
-        ASSERT(m_importableFunctions.get()[i].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
-        m_instances.get()[i] = nullptr;
+        new (&m_jsValues.get()[i]) WriteBarrier<Unknown>();
+        m_jsValues.get()[i].setStartingValue(jsNull());
     }
 }
 
+RefPtr<Table> Table::tryCreate(uint32_t initial, Optional<uint32_t> maximum, TableElementType type)
+{
+    if (!isValidLength(initial))
+        return nullptr;
+    switch (type) {
+    case TableElementType::Funcref:
+        return adoptRef(new FuncRefTable(initial, maximum));
+    case TableElementType::Anyref:
+        return adoptRef(new Table(initial, maximum));
+    }
+}
+
 Optional<uint32_t> Table::grow(uint32_t delta)
 {
+    RELEASE_ASSERT(m_owner);
     if (delta == 0)
         return length();
 
+    auto locker = holdLock(m_owner->cellLock());
+
     using Checked = Checked<uint32_t, RecordOverflow>;
     Checked newLengthChecked = length();
     newLengthChecked += delta;
@@ -108,27 +112,83 @@
         return true;
     };
 
-    if (!checkedGrow(m_importableFunctions))
+    if (auto* funcRefTable = asFuncrefTable()) {
+        if (!checkedGrow(funcRefTable->m_importableFunctions))
+            return WTF::nullopt;
+        if (!checkedGrow(funcRefTable->m_instances))
+            return WTF::nullopt;
+    }
+
+    if (!checkedGrow(m_jsValues))
         return WTF::nullopt;
-    if (!checkedGrow(m_instances))
-        return WTF::nullopt;
 
     setLength(newLength);
-
     return newLength;
 }
 
-void Table::clearFunction(uint32_t index)
+void Table::clear(uint32_t index)
 {
     RELEASE_ASSERT(index < length());
-    m_importableFunctions.get()[index & m_mask] = WasmToWasmImportableFunction();
-    ASSERT(m_importableFunctions.get()[index & m_mask].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
-    m_instances.get()[index & m_mask] = nullptr;
+    RELEASE_ASSERT(m_owner);
+    if (auto* funcRefTable = asFuncrefTable()) {
+        funcRefTable->m_importableFunctions.get()[index & m_mask] = WasmToWasmImportableFunction();
+        ASSERT(funcRefTable->m_importableFunctions.get()[index & m_mask].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
+        funcRefTable->m_instances.get()[index & m_mask] = nullptr;
+    }
+    m_jsValues.get()[index & m_mask].setStartingValue(jsNull());
 }
 
-void Table::setFunction(uint32_t index, WasmToWasmImportableFunction function, Instance* instance)
+void Table::set(uint32_t index, JSValue value)
 {
     RELEASE_ASSERT(index < length());
+    RELEASE_ASSERT(isAnyrefTable());
+    RELEASE_ASSERT(m_owner);
+    clear(index);
+    m_jsValues.get()[index & m_mask].set(*m_owner->vm(), m_owner, value);
+}
+
+JSValue Table::get(uint32_t index) const
+{
+    RELEASE_ASSERT(index < length());
+    RELEASE_ASSERT(m_owner);
+    return m_jsValues.get()[index & m_mask].get();
+}
+
+void Table::visitChildren(SlotVisitor& visitor)
+{
+    RELEASE_ASSERT(m_owner);
+    auto locker = holdLock(m_owner->cellLock());
+    for (unsigned i = 0; i < m_length; ++i)
+        visitor.append(m_jsValues.get()[i]);
+}
+
+FuncRefTable* Table::asFuncrefTable()
+{
+    return m_type == TableElementType::Funcref ? static_cast<FuncRefTable*>(this) : nullptr;
+}
+
+FuncRefTable::FuncRefTable(uint32_t initial, Optional<uint32_t> maximum)
+    : Table(initial, maximum, TableElementType::Funcref)
+{
+    // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
+    // But for now, we're not doing that.
+    m_importableFunctions = MallocPtr<WasmToWasmImportableFunction>::malloc((sizeof(WasmToWasmImportableFunction) * Checked<size_t>(allocatedLength(m_length))).unsafeGet());
+    // FIXME this over-allocates and could be smarter about not committing all of that memory https://bugs.webkit.org/show_bug.cgi?id=181425
+    m_instances = MallocPtr<Instance*>::malloc((sizeof(Instance*) * Checked<size_t>(allocatedLength(m_length))).unsafeGet());
+    for (uint32_t i = 0; i < allocatedLength(m_length); ++i) {
+        new (&m_importableFunctions.get()[i]) WasmToWasmImportableFunction();
+        ASSERT(m_importableFunctions.get()[i].signatureIndex == Wasm::Signature::invalidIndex); // We rely on this in compiled code.
+        m_instances.get()[i] = nullptr;
+    }
+}
+
+void FuncRefTable::setFunction(uint32_t index, JSObject* optionalWrapper, WasmToWasmImportableFunction function, Instance* instance)
+{
+    RELEASE_ASSERT(index < length());
+    RELEASE_ASSERT(m_owner);
+    clear(index);
+    if (optionalWrapper)
+        m_jsValues.get()[index & m_mask].set(*m_owner->vm(), m_owner, optionalWrapper);
     m_importableFunctions.get()[index & m_mask] = function;
     m_instances.get()[index & m_mask] = instance;
 }

Modified: trunk/Source/_javascript_Core/wasm/WasmTable.h (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmTable.h	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmTable.h	2019-06-06 03:14:47 UTC (rev 246139)
@@ -29,6 +29,7 @@
 
 #include "WasmFormat.h"
 #include "WasmLimits.h"
+#include "WriteBarrier.h"
 #include <wtf/MallocPtr.h>
 #include <wtf/Optional.h>
 #include <wtf/Ref.h>
@@ -37,39 +38,77 @@
 namespace JSC { namespace Wasm {
 
 class Instance;
+class FuncRefTable;
 
 class Table : public ThreadSafeRefCounted<Table> {
+    WTF_MAKE_NONCOPYABLE(Table);
+    WTF_MAKE_FAST_ALLOCATED(Table);
 public:
-    static RefPtr<Table> tryCreate(uint32_t initial, Optional<uint32_t> maximum);
+    static RefPtr<Table> tryCreate(uint32_t initial, Optional<uint32_t> maximum, TableElementType);
 
-    JS_EXPORT_PRIVATE ~Table();
+    JS_EXPORT_PRIVATE ~Table() = default;
 
     Optional<uint32_t> maximum() const { return m_maximum; }
     uint32_t length() const { return m_length; }
-    Optional<uint32_t> grow(uint32_t delta) WARN_UNUSED_RETURN;
-    void clearFunction(uint32_t);
-    void setFunction(uint32_t, WasmToWasmImportableFunction, Instance*);
 
-    static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(Table, m_importableFunctions); }
-    static ptrdiff_t offsetOfInstances() { return OBJECT_OFFSETOF(Table, m_instances); }
     static ptrdiff_t offsetOfLength() { return OBJECT_OFFSETOF(Table, m_length); }
     static ptrdiff_t offsetOfMask() { return OBJECT_OFFSETOF(Table, m_mask); }
 
     static uint32_t allocatedLength(uint32_t length);
     uint32_t mask() const { return m_mask; }
+
+    void setOwner(JSObject* owner)
+    {
+        ASSERT(!m_owner);
+        ASSERT(owner);
+        m_owner = owner;
+    }
+
+    TableElementType type() const { return m_type; }
+    bool isAnyrefTable() const { return m_type == TableElementType::Anyref; }
+    FuncRefTable* asFuncrefTable();
+
     static bool isValidLength(uint32_t length) { return length < maxTableEntries; }
 
-private:
-    Table(uint32_t initial, Optional<uint32_t> maximum);
+    void clear(uint32_t);
+    void set(uint32_t, JSValue);
+    JSValue get(uint32_t) const;
 
+    Optional<uint32_t> grow(uint32_t delta);
+
+    void visitChildren(SlotVisitor&);
+
+protected:
+    Table(uint32_t initial, Optional<uint32_t> maximum, TableElementType = TableElementType::Anyref);
+
     void setLength(uint32_t);
 
+    uint32_t m_length;
+    uint32_t m_mask;
+    const TableElementType m_type;
+    const Optional<uint32_t> m_maximum;
+
+    MallocPtr<WriteBarrier<Unknown>> m_jsValues;
+    JSObject* m_owner;
+};
+
+class FuncRefTable : public Table {
+public:
+    JS_EXPORT_PRIVATE ~FuncRefTable() = default;
+
+    void setFunction(uint32_t, JSObject*, WasmToWasmImportableFunction, Instance*);
+
+    static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(FuncRefTable, m_importableFunctions); }
+    static ptrdiff_t offsetOfInstances() { return OBJECT_OFFSETOF(FuncRefTable, m_instances); }
+
+private:
+    FuncRefTable(uint32_t initial, Optional<uint32_t> maximum);
+
     MallocPtr<WasmToWasmImportableFunction> m_importableFunctions;
     // call_indirect needs to do an Instance check to potentially context switch when calling a function to another instance. We can hold raw pointers to Instance here because the embedder ensures that Table keeps all the instances alive. We couldn't hold a Ref here because it would cause cycles.
     MallocPtr<Instance*> m_instances;
-    uint32_t m_length;
-    uint32_t m_mask;
-    Optional<uint32_t> m_maximum;
+
+    friend class Table;
 };
 
 } } // namespace JSC::Wasm

Modified: trunk/Source/_javascript_Core/wasm/WasmValidate.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/WasmValidate.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/WasmValidate.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -100,8 +100,13 @@
     Result WARN_UNUSED_RETURN addLocal(Type, uint32_t);
     ExpressionType addConstant(Type type, uint64_t) { return type; }
 
+    // References
     Result WARN_UNUSED_RETURN addRefIsNull(ExpressionType& value, ExpressionType& result);
 
+    // Tables
+    Result WARN_UNUSED_RETURN addTableGet(ExpressionType& idx, ExpressionType& result);
+    Result WARN_UNUSED_RETURN addTableSet(ExpressionType& idx, ExpressionType& value);
+
     // Locals
     Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
     Result WARN_UNUSED_RETURN setLocal(uint32_t index, ExpressionType value);
@@ -171,6 +176,24 @@
     return { };
 }
 
+auto Validate::addTableGet(ExpressionType& idx, 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);
+
+    return { };
+}
+
+auto Validate::addTableSet(ExpressionType& idx, 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);
+
+    return { };
+}
+
 auto Validate::addRefIsNull(ExpressionType& value, ExpressionType& result) -> Result
 {
     result = Type::I32;
@@ -346,6 +369,7 @@
 
 auto Validate::addCallIndirect(const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
 {
+    WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Funcref, "Table must have type Anyfunc to call");
     const auto argumentCount = signature.argumentCount();
     WASM_VALIDATOR_FAIL_IF(argumentCount != args.size() - 1, "arity mismatch in call_indirect, got ", args.size() - 1, " arguments, expected ", argumentCount);
 

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -47,6 +47,7 @@
     }
 
     auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure, WTFMove(table));
+    instance->table()->setOwner(instance);
     instance->finishCreation(vm);
     return instance;
 }
@@ -60,12 +61,6 @@
     : Base(vm, structure)
     , m_table(WTFMove(table))
 {
-    // FIXME: It might be worth trying to pre-allocate maximum here. The spec recommends doing so.
-    // But for now, we're not doing that.
-    // FIXME this over-allocates and could be smarter about not committing all of that memory https://bugs.webkit.org/show_bug.cgi?id=181425
-    m_jsFunctions = MallocPtr<WriteBarrier<JSObject>>::malloc((sizeof(WriteBarrier<JSObject>) * Checked<size_t>(allocatedLength())).unsafeGet());
-    for (uint32_t i = 0; i < allocatedLength(); ++i)
-        new(&m_jsFunctions.get()[i]) WriteBarrier<JSObject>();
 }
 
 void JSWebAssemblyTable::finishCreation(VM& vm)
@@ -85,9 +80,7 @@
     ASSERT_GC_OBJECT_INHERITS(thisObject, info());
 
     Base::visitChildren(thisObject, visitor);
-
-    for (unsigned i = 0; i < thisObject->length(); ++i)
-        visitor.append(thisObject->m_jsFunctions.get()[i]);
+    thisObject->table()->visitChildren(visitor);
 }
 
 bool JSWebAssemblyTable::grow(uint32_t delta)
@@ -94,46 +87,42 @@
 {
     if (delta == 0)
         return true;
+    return !!m_table->grow(delta);
+}
 
-    size_t oldLength = length();
-
-    auto grew = m_table->grow(delta);
-    if (!grew)
-        return false;
-
-    size_t newLength = grew.value();
-    if (newLength > m_table->allocatedLength(oldLength))
-        // FIXME this over-allocates and could be smarter about not committing all of that memory https://bugs.webkit.org/show_bug.cgi?id=181425
-        m_jsFunctions.realloc((sizeof(WriteBarrier<JSObject>) * Checked<size_t>(m_table->allocatedLength(newLength))).unsafeGet());
-
-    for (size_t i = oldLength; i < m_table->allocatedLength(newLength); ++i)
-        new (&m_jsFunctions.get()[i]) WriteBarrier<JSObject>();
-
-    return true;
+JSValue JSWebAssemblyTable::get(uint32_t index)
+{
+    RELEASE_ASSERT(index < length());
+    return m_table->get(index);
 }
 
-JSObject* JSWebAssemblyTable::getFunction(uint32_t index)
+void JSWebAssemblyTable::set(uint32_t index, JSValue value)
 {
     RELEASE_ASSERT(index < length());
-    return m_jsFunctions.get()[index & m_table->mask()].get();
+    RELEASE_ASSERT(m_table->isAnyrefTable());
+    m_table->set(index, value);
 }
 
-void JSWebAssemblyTable::clearFunction(uint32_t index)
+void JSWebAssemblyTable::set(uint32_t index, WebAssemblyFunction* function)
 {
-    m_table->clearFunction(index);
-    m_jsFunctions.get()[index & m_table->mask()] = WriteBarrier<JSObject>();
+    RELEASE_ASSERT(index < length());
+    RELEASE_ASSERT(m_table->asFuncrefTable());
+    auto& subThis = *static_cast<Wasm::FuncRefTable*>(&m_table.get());
+    subThis.setFunction(index, function, function->importableFunction(), &function->instance()->instance());
 }
 
-void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyFunction* function)
+void JSWebAssemblyTable::set(uint32_t index, WebAssemblyWrapperFunction* function)
 {
-    m_table->setFunction(index, function->importableFunction(), &function->instance()->instance());
-    m_jsFunctions.get()[index & m_table->mask()].set(vm, this, function);
+    RELEASE_ASSERT(index < length());
+    RELEASE_ASSERT(m_table->asFuncrefTable());
+    auto& subThis = *static_cast<Wasm::FuncRefTable*>(&m_table.get());
+    subThis.setFunction(index, function, function->importableFunction(), &function->instance()->instance());
 }
 
-void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyWrapperFunction* function)
+void JSWebAssemblyTable::clear(uint32_t index)
 {
-    m_table->setFunction(index, function->importableFunction(), &function->instance()->instance());
-    m_jsFunctions.get()[index & m_table->mask()].set(vm, this, function);
+    RELEASE_ASSERT(index < length());
+    m_table->clear(index);
 }
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h	2019-06-06 03:14:47 UTC (rev 246139)
@@ -52,10 +52,11 @@
     uint32_t length() const { return m_table->length(); }
     uint32_t allocatedLength() const { return m_table->allocatedLength(length()); }
     bool grow(uint32_t delta) WARN_UNUSED_RETURN;
-    JSObject* getFunction(uint32_t);
-    void clearFunction(uint32_t);
-    void setFunction(VM&, uint32_t, WebAssemblyFunction*);
-    void setFunction(VM&, uint32_t, WebAssemblyWrapperFunction*);
+    JSValue get(uint32_t);
+    void set(uint32_t, WebAssemblyFunction*);
+    void set(uint32_t, WebAssemblyWrapperFunction*);
+    void set(uint32_t, JSValue);
+    void clear(uint32_t);
 
     Wasm::Table* table() { return m_table.ptr(); }
 
@@ -66,7 +67,6 @@
     static void visitChildren(JSCell*, SlotVisitor&);
 
     Ref<Wasm::Table> m_table;
-    MallocPtr<WriteBarrier<JSObject>> m_jsFunctions;
 };
 
 } // namespace JSC

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -280,6 +280,11 @@
                     return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
             }
 
+            auto expectedType = moduleInformation.tableInformation.type();
+            auto actualType = table->table()->type();
+            if (expectedType != actualType)
+                return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided a 'type' that is wrong")));
+
             // ii. Append v to tables.
             // iii. Append v.[[Table]] to imports.
             m_instance->setTable(vm, table);
@@ -301,7 +306,7 @@
         if (!!moduleInformation.tableInformation && !hasTableImport) {
             RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
             // We create a Table when it's a Table definition.
-            RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+            RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum(), moduleInformation.tableInformation.type());
             if (!wasmTable)
                 return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
             JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->webAssemblyTableStructure(), wasmTable.releaseNonNull());
@@ -536,12 +541,12 @@
                     // Because a WebAssemblyWrapperFunction can never wrap another WebAssemblyWrapperFunction,
                     // the only type this could be is WebAssemblyFunction.
                     RELEASE_ASSERT(wasmFunction);
-                    table->setFunction(vm, tableIndex, wasmFunction);
+                    table->set(tableIndex, wasmFunction);
                     ++tableIndex;
                     continue;
                 }
 
-                table->setFunction(vm, tableIndex,
+                table->set(tableIndex,
                     WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex));
                 ++tableIndex;
                 continue;
@@ -557,7 +562,7 @@
             WebAssemblyFunction* function = WebAssemblyFunction::create(
                 vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
 
-            table->setFunction(vm, tableIndex, function);
+            table->set(tableIndex, function);
             ++tableIndex;
         }
     });

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -58,6 +58,7 @@
         memoryDescriptor = jsCast<JSObject*>(argument);
     }
 
+    Wasm::TableElementType type;
     {
         Identifier elementIdent = Identifier::fromString(&vm, "element");
         JSValue elementValue = memoryDescriptor->get(exec, elementIdent);
@@ -64,8 +65,12 @@
         RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
         String elementString = elementValue.toWTFString(exec);
         RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
-        if (elementString != "anyfunc")
-            return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table expects its 'element' field to be the string 'anyfunc'"_s)));
+        if (elementString == "anyfunc")
+            type = Wasm::TableElementType::Funcref;
+        else if (elementString == "anyref")
+            type = Wasm::TableElementType::Anyref;
+        else
+            return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table expects its 'element' field to be the string 'anyfunc' or 'anyref'"_s)));
     }
 
     Identifier initialIdent = Identifier::fromString(&vm, "initial");
@@ -90,7 +95,7 @@
         }
     }
 
-    RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(initial, maximum);
+    RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(initial, maximum, type);
     if (!wasmTable) {
         return JSValue::encode(throwException(exec, throwScope,
             createRangeError(exec, "couldn't create Table"_s)));

Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp	2019-06-06 03:14:47 UTC (rev 246139)
@@ -109,9 +109,7 @@
     if (index >= table->length())
         return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.get expects an integer less than the length of the table"_s)));
 
-    if (JSObject* result = table->getFunction(index))
-        return JSValue::encode(result);
-    return JSValue::encode(jsNull());
+    return JSValue::encode(table->get(index));
 }
 
 static EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec)
@@ -123,10 +121,6 @@
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
 
     JSValue value = exec->argument(1);
-    WebAssemblyFunction* wasmFunction;
-    WebAssemblyWrapperFunction* wasmWrapperFunction;
-    if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction))
-        return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s)));
 
     uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
     RETURN_IF_EXCEPTION(throwScope, encodedJSValue());
@@ -134,16 +128,24 @@
     if (index >= table->length())
         return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, "WebAssembly.Table.prototype.set expects an integer less than the length of the table"_s)));
 
-    if (value.isNull())
-        table->clearFunction(index);
-    else {
-        ASSERT(value.isObject() && isWebAssemblyHostFunction(vm, jsCast<JSObject*>(value), wasmFunction, wasmWrapperFunction));
-        ASSERT(!!wasmFunction || !!wasmWrapperFunction);
-        if (wasmFunction)
-            table->setFunction(vm, index, wasmFunction);
-        else
-            table->setFunction(vm, index, wasmWrapperFunction);
-    }
+    if (table->table()->asFuncrefTable()) {
+        WebAssemblyFunction* wasmFunction;
+        WebAssemblyWrapperFunction* wasmWrapperFunction;
+        if (!value.isNull() && !isWebAssemblyHostFunction(vm, value, wasmFunction, wasmWrapperFunction))
+            return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, "WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function"_s)));
+
+        if (value.isNull())
+            table->clear(index);
+        else {
+            ASSERT(value.isObject() && isWebAssemblyHostFunction(vm, jsCast<JSObject*>(value), wasmFunction, wasmWrapperFunction));
+            ASSERT(!!wasmFunction || !!wasmWrapperFunction);
+            if (wasmFunction)
+                table->set(index, wasmFunction);
+            else
+                table->set(index, wasmWrapperFunction);
+        }
+    } else
+        table->set(index, value);
     
     return JSValue::encode(jsUndefined());
 }

Modified: trunk/Source/_javascript_Core/wasm/wasm.json (246138 => 246139)


--- trunk/Source/_javascript_Core/wasm/wasm.json	2019-06-06 02:17:15 UTC (rev 246138)
+++ trunk/Source/_javascript_Core/wasm/wasm.json	2019-06-06 03:14:47 UTC (rev 246139)
@@ -18,7 +18,7 @@
     },
     "value_type": ["i32", "i64", "f32", "f64", "anyref"],
     "block_type": ["i32", "i64", "f32", "f64", "void", "anyref"],
-    "elem_type": ["anyfunc"],
+    "elem_type": ["anyfunc","anyref"],
     "external_kind": {
         "Function": { "type": "uint8", "value": 0 },
         "Table":    { "type": "uint8", "value": 1 },
@@ -66,6 +66,8 @@
         "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" },
         "get_global":          { "category": "special",    "value":  35, "return": ["any"],      "parameter": [],                       "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "read a global variable" },
         "set_global":          { "category": "special",    "value":  36, "return": [],           "parameter": ["any"],                  "immediate": [{"name": "global_index",   "type": "varuint32"}],                                            "description": "write a global variable" },
+        "table.get":           { "category": "special",    "value":  37, "return": ["anyref"],   "parameter": ["i32"],                  "immediate": [],                                                                                           "description": "get a table value" },
+        "table.set":           { "category": "special",    "value":  38, "return": [],           "parameter": ["i32", "anyref"],        "immediate": [],                                                                                           "description": "set a table value" },
         "call":                { "category": "call",       "value":  16, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "function_index", "type": "varuint32"}],                                            "description": "call a function by its index" },
         "call_indirect":       { "category": "call",       "value":  17, "return": ["call"],     "parameter": ["call"],                 "immediate": [{"name": "type_index",     "type": "varuint32"}, {"name": "reserved", "type": "varuint1"}],  "description": "call a function indirect with an expected signature" },
         "i32.load8_s":         { "category": "memory",     "value":  44, "return": ["i32"],      "parameter": ["addr"],                 "immediate": [{"name": "flags",          "type": "varuint32"}, {"name": "offset",   "type": "varuint32"}], "description": "load from memory" },
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to