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" },