Diff
Modified: trunk/JSTests/ChangeLog (246570 => 246571)
--- trunk/JSTests/ChangeLog 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/ChangeLog 2019-06-18 22:01:02 UTC (rev 246571)
@@ -1,3 +1,83 @@
+2019-06-18 Justin Michaud <justin_mich...@apple.com>
+
+ [WASM-References] Add support for multiple tables
+ https://bugs.webkit.org/show_bug.cgi?id=198760
+
+ Reviewed by Saam Barati.
+
+ * wasm/Builder.js:
+ * wasm/js-api/call-indirect.js:
+ (const.oneTable):
+ (const.multiTable):
+ (multiTable):
+ (multiTable.Polyphic2Import):
+ (multiTable.VirtualImport):
+ (const.wasmModuleWhichImportJS): Deleted.
+ (const.makeTable): Deleted.
+ (): Deleted.
+ (Polyphic2Import): Deleted.
+ (VirtualImport): Deleted.
+ * wasm/js-api/table.js:
+ (new.WebAssembly.Module):
+ (assert.throws):
+ (assertBadTableImport):
+ (assert.truthy):
+ (assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.
+ * wasm/references/anyref_table.js:
+ * wasm/references/anyref_table_import.js:
+ (makeImport):
+ (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
+ (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
+ * wasm/references/multitable.js: Added.
+ (assert.throws.1.exports.set_tbl0):
+ (assert.throws):
+ (assert.eq):
+ * wasm/references/validation.js:
+ (assert.throws.new.WebAssembly.Module.bin):
+ (assert.throws):
+ * wasm/spec-tests/imports.wast.js:
+ * wasm/wasm.json:
+
+ * wasm/Builder.js:
+ * wasm/js-api/call-indirect.js:
+ (const.oneTable):
+ (const.multiTable):
+ (multiTable):
+ (multiTable.Polyphic2Import):
+ (multiTable.VirtualImport):
+ (const.wasmModuleWhichImportJS): Deleted.
+ (const.makeTable): Deleted.
+ (): Deleted.
+ (Polyphic2Import): Deleted.
+ (VirtualImport): Deleted.
+ * wasm/js-api/table.js:
+ (new.WebAssembly.Module):
+ (assert.throws):
+ (assertBadTableImport):
+ (assert.truthy):
+ (assert.throws.new.WebAssembly.Module.builder.WebAssembly): Deleted.
+ * wasm/references/anyref_table.js:
+ * wasm/references/anyref_table_import.js:
+ (makeImport):
+ (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl.makeImport):
+ (string_appeared_here.fullGC.assert.eq.1.exports.get_tbl):
+ * wasm/references/func_ref.js:
+ (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.fun): Deleted.
+ (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly.assert.throws): Deleted.
+ (GetLocal.0.I32Const.0.TableSet.End.End.WebAssembly): Deleted.
+ * wasm/references/multitable.js: Added.
+ (assert.throws.1.exports.set_tbl0):
+ (assert.throws):
+ (assert.eq):
+ (string_appeared_here.tableInsanity):
+ (I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly.):
+ (I32Const.0.GetLocal.0.TableSet.1.End.End.WebAssembly):
+ * wasm/references/validation.js:
+ (assert.throws.new.WebAssembly.Module.bin):
+ (assert.throws):
+ * wasm/spec-tests/imports.wast.js:
+ * wasm/wasm.json:
+
2019-06-18 Alexey Shvayka <shvaikal...@gmail.com>
[ESNExt] String.prototype.matchAll
Modified: trunk/JSTests/wasm/Builder.js (246570 => 246571)
--- trunk/JSTests/wasm/Builder.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/Builder.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -306,6 +306,7 @@
case "target_count": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
case "target_table": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
case "reserved": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
+ case "table_index": break; // improve checking https://bugs.webkit.org/show_bug.cgi?id=163421
default: throw new Error(`Implementation problem: unhandled immediate "${expect.name}" on "${op}"`);
}
}
Modified: trunk/JSTests/wasm/js-api/call-indirect.js (246570 => 246571)
--- trunk/JSTests/wasm/js-api/call-indirect.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/js-api/call-indirect.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -1,7 +1,7 @@
import * as assert from '../assert.js';
import Builder from '../Builder.js';
-const wasmModuleWhichImportJS = () => {
+const _oneTable_ = () => {
const builder = (new Builder())
.Type().End()
.Import()
@@ -31,6 +31,39 @@
return module;
};
+const multiTable = () => {
+ const builder = (new Builder())
+ .Type().End()
+ .Import()
+ .Function("imp", "func", { params: ["i32"] })
+ .Table("imp", "table0", { initial: 0, maximum: 0, element: "anyfunc"})
+ .Table("imp", "table", { initial: 1, maximum: 1, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Export()
+ .Function("changeCounter")
+ .Function("callFunc")
+ .End()
+ .Code()
+ .Function("changeCounter", { params: ["i32", "i32"] })
+ .I32Const(42)
+ .GetLocal(0)
+ .I32Add()
+ .GetLocal(1)
+ .CallIndirect(0, 1) // Calls table[0](param[0] + 42).
+ .End()
+ .Function("callFunc", { params: ["i32"] })
+ .GetLocal(0)
+ .Call(0) // Calls func(param[0] + 42)
+ .End()
+ .End();
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ return module;
+};
+
+for (const wasmModuleWhichImportJS of [oneTable, multiTable]) {
+
const makeTable = () => {
return new WebAssembly.Table({initial: 1, maximum: 1, element: "anyfunc"});
};
@@ -40,7 +73,7 @@
const counterSetter = v => counter = v;
const table = makeTable();
const module = wasmModuleWhichImportJS();
- const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table} });
+ const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
table.set(0, instance.exports.callFunc);
for (let i = 0; i < 4096; ++i) {
// Invoke this a bunch of times to make sure the IC in the wasm -> JS stub works correctly.
@@ -57,11 +90,11 @@
const module = wasmModuleWhichImportJS();
const tableA = makeTable();
- const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA} });
+ const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
tableA.set(0, instanceA.exports.callFunc);
const tableB = makeTable();
- const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB} });
+ const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
tableB.set(0, instanceB.exports.callFunc);
for (let i = 0; i < 2048; ++i) {
instanceA.exports.changeCounter(i, 0);
@@ -93,7 +126,7 @@
let instances = [];
for (let i = 0; i < num; ++i) {
let table = makeTable();
- instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table} });
+ instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table, table0: new WebAssembly.Table({initial: 0, maximum: 0, element: "anyfunc"}) } });
table.set(0, instances[i].exports.callFunc);
}
for (let i = 0; i < 2048; ++i) {
@@ -104,3 +137,5 @@
}
}
})();
+
+}
Modified: trunk/JSTests/wasm/js-api/table.js (246570 => 246571)
--- trunk/JSTests/wasm/js-api/table.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/js-api/table.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -13,7 +13,7 @@
.End()
.Code()
.End();
- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 34: Cannot have more than one Table for now");
+ new WebAssembly.Module(builder.WebAssembly().get())
}
{
@@ -38,7 +38,7 @@
.End()
.Code()
.End();
- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 17: Table count of 2 is invalid, at most 1 is allowed for now (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
+ new WebAssembly.Module(builder.WebAssembly().get())
}
{
@@ -73,10 +73,31 @@
.CallIndirect(0, 1)
.End()
.End();
- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6: call_indirect's 'reserved' varuint1 must be 0x0, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
+ assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 6: call_indirect's table index 1 invalid, limit is 1, in function at index 0 (evaluating 'new WebAssembly.Module(builder.WebAssembly().get())')");
}
{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial:20, element:"anyfunc"})
+ .Table({initial:20, element:"anyfunc"})
+ .End()
+ .Export()
+ .Function("foo")
+ .End()
+ .Code()
+ .Function("foo", {params: ["i32"]})
+ .GetLocal(0)
+ .GetLocal(0)
+ .CallIndirect(0, 1)
+ .End()
+ .End();
+ new WebAssembly.Module(builder.WebAssembly().get())
+}
+
+{
// Can't export an undefined table
const builder = new Builder()
.Type().End()
@@ -186,7 +207,7 @@
.Function().End()
.Code()
.End();
- assert.throws(() => new WebAssembly.Module(builder.WebAssembly().get()), WebAssembly.CompileError, "WebAssembly.Module doesn't parse at byte 39: Cannot have more than one Table for now");
+ new WebAssembly.Module(builder.WebAssembly().get())
}
@@ -320,3 +341,26 @@
assert.eq(instance.exports.table.length, 20);
assert.truthy(instance.exports.table instanceof WebAssembly.Table);
}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 0, maximum: 1, element: "anyfunc"})
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Export()
+ .Table("table0", 0)
+ .Table("table", 1)
+ .Table("table2", 1)
+ .End()
+ .Code().End();
+
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ const instance = new WebAssembly.Instance(module);
+ assert.eq(instance.exports.table, instance.exports.table2);
+ assert.eq(instance.exports.table.length, 20);
+ assert.eq(instance.exports.table0.length, 0);
+ assert.truthy(instance.exports.table instanceof WebAssembly.Table);
+}
Modified: trunk/JSTests/wasm/references/anyref_table.js (246570 => 246571)
--- trunk/JSTests/wasm/references/anyref_table.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/references/anyref_table.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -18,12 +18,12 @@
.Function("set_tbl", { params: ["anyref"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(0)
.End()
.Function("get_tbl", { params: [], ret: "anyref" })
.I32Const(0)
- .TableGet()
+ .TableGet(0)
.End()
.Function("tbl_is_null", { params: [], ret: "i32" })
Modified: trunk/JSTests/wasm/references/anyref_table_import.js (246570 => 246571)
--- trunk/JSTests/wasm/references/anyref_table_import.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/references/anyref_table_import.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -22,12 +22,12 @@
.Function("set_tbl", { params: ["anyref"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(0)
.End()
.Function("get_tbl", { params: [], ret: "anyref" })
.I32Const(0)
- .TableGet()
+ .TableGet(0)
.End()
.Function("tbl_is_null", { params: [], ret: "i32" })
@@ -88,12 +88,12 @@
.Function("set_tbl", { params: ["anyref"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(0)
.End()
.Function("get_tbl", { params: [], ret: "anyref" })
.I32Const(0)
- .TableGet()
+ .TableGet(0)
.End()
.Function("tbl_is_null", { params: [], ret: "i32" })
@@ -127,12 +127,12 @@
.Function("set_tbl", { params: ["anyref"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(0)
.End()
.Function("get_tbl", { params: [], ret: "anyref" })
.I32Const(0)
- .TableGet()
+ .TableGet(0)
.End()
.Function("tbl_is_null", { params: [], ret: "i32" })
Modified: trunk/JSTests/wasm/references/func_ref.js (246570 => 246571)
--- trunk/JSTests/wasm/references/func_ref.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/references/func_ref.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -257,7 +257,7 @@
.Function("h", { params: ["i32"], ret: "void" })
.GetLocal(0)
.I32Const(0)
- .TableSet()
+ .TableSet(0)
.End()
.End().WebAssembly().get()), Error, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module')");
@@ -267,6 +267,7 @@
.Type().End()
.Function().End()
.Table()
+ .Table({initial: 0, element: "anyref"})
.Table({initial: 1, element: "anyfunc"})
.End()
.Global()
@@ -291,11 +292,11 @@
.Function("call_glob", { params: ["i32"], ret: "i32" })
.I32Const(0)
.GetGlobal(0)
- .TableSet()
+ .TableSet(1)
.GetLocal(0)
.I32Const(0)
- .CallIndirect(2,0)
+ .CallIndirect(2,1)
.End()
.Function("ret_20", { params: ["i32"], ret: "i32" })
@@ -328,6 +329,7 @@
.Type().End()
.Function().End()
.Table()
+ .Table({initial: 0, element: "anyref"})
.Table({initial: 1, element: "anyfunc"})
.End()
.Export()
@@ -338,12 +340,12 @@
.Function("set", { params: ["anyfunc"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(1)
.End()
.Function("get", { params: [], ret: "anyfunc" })
.I32Const(0)
- .TableGet()
+ .TableGet(1)
.End()
.End().WebAssembly().get()));
@@ -405,7 +407,7 @@
.GetLocal(0)
.I32Const(0)
.RefFunc(0)
- .TableSet()
+ .TableSet(0)
.I32Const(0)
.CallIndirect(0, 0)
.End()
@@ -414,7 +416,7 @@
.RefFunc(1)
.I32Const(0)
.RefFunc(0)
- .TableSet()
+ .TableSet(0)
.I32Const(0)
.CallIndirect(0, 0)
.End()
Added: trunk/JSTests/wasm/references/multitable.js (0 => 246571)
--- trunk/JSTests/wasm/references/multitable.js (rev 0)
+++ trunk/JSTests/wasm/references/multitable.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -0,0 +1,460 @@
+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: 0, maximum: 0, element: "anyref"})
+ .Table({initial: 20, maximum: 30, element: "anyref"})
+ .End()
+ .Export()
+ .Function("set_tbl")
+ .Function("get_tbl")
+ .Function("get_tbl0")
+ .Function("set_tbl0")
+ .Table("tbl", 1)
+ .End()
+ .Code()
+ .Function("set_tbl", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1)
+ .End()
+
+ .Function("get_tbl", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(1)
+ .End()
+
+ .Function("get_tbl0", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(0)
+ .End()
+
+ .Function("set_tbl0", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(0)
+ .End()
+ .End().WebAssembly().get()));
+
+ fullGC()
+
+ assert.eq($1.exports.get_tbl(), null)
+
+ $1.exports.set_tbl("hi")
+ fullGC()
+ assert.eq($1.exports.get_tbl(), "hi")
+ assert.eq($1.exports.tbl.get(0), "hi")
+ assert.eq($1.exports.tbl.get(1), null)
+
+ assert.throws(() => $1.exports.get_tbl0(), Error, "Out of bounds table access (evaluating 'func(...args)')");
+ assert.throws(() => $1.exports.set_tbl0(null), Error, "Out of bounds table access (evaluating 'func(...args)')");
+}
+
+{
+ const tbl = new WebAssembly.Table({initial:0, element:"anyref"});
+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Import()
+ .Table("imp", "tbl", {initial: 0, element: "anyref"})
+ .End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyref"})
+ .End()
+ .Export()
+ .Function("set_tbl")
+ .Function("get_tbl")
+ .Function("get_tbl0")
+ .Function("set_tbl0")
+ .Table("tbl", 1)
+ .End()
+ .Code()
+ .Function("set_tbl", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1)
+ .End()
+
+ .Function("get_tbl", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(1)
+ .End()
+
+ .Function("get_tbl0", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(0)
+ .End()
+
+ .Function("set_tbl0", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(0)
+ .End()
+ .End().WebAssembly().get()), { imp: { tbl }});
+
+ fullGC()
+
+ assert.eq($1.exports.get_tbl(), null)
+
+ $1.exports.set_tbl("hi")
+ fullGC()
+ assert.eq($1.exports.get_tbl(), "hi")
+ assert.eq($1.exports.tbl.get(0), "hi")
+ assert.eq($1.exports.tbl.get(1), null)
+
+ assert.throws(() => $1.exports.get_tbl0(), Error, "Out of bounds table access (evaluating 'func(...args)')");
+ assert.throws(() => $1.exports.set_tbl0(null), Error, "Out of bounds table access (evaluating 'func(...args)')");
+}
+
+{
+ const tbl = new WebAssembly.Table({initial:1, element:"anyref"});
+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Import()
+ .Table("imp", "tbl", {initial: 1, element: "anyref"})
+ .End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyref"})
+ .End()
+ .Export()
+ .Function("set_tbl")
+ .Function("get_tbl")
+ .Function("get_tbl0")
+ .Function("set_tbl0")
+ .Table("tbl", 1)
+ .End()
+ .Code()
+ .Function("set_tbl", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1)
+ .End()
+
+ .Function("get_tbl", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(1)
+ .End()
+
+ .Function("get_tbl0", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(0)
+ .End()
+
+ .Function("set_tbl0", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(0)
+ .End()
+ .End().WebAssembly().get()), { imp: { tbl }});
+
+ fullGC()
+
+ assert.eq($1.exports.get_tbl(), null)
+
+ $1.exports.set_tbl("hi")
+ fullGC()
+ $1.exports.set_tbl0(null)
+ assert.eq($1.exports.get_tbl(), "hi")
+ assert.eq($1.exports.get_tbl0(), null)
+ assert.eq($1.exports.tbl.get(0), "hi")
+ assert.eq($1.exports.tbl.get(1), null)
+ assert.eq(tbl.get(0), null)
+}
+
+{
+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 30, element: "anyfunc"})
+ .Table({initial: 2, maximum: 30, element: "anyfunc"})
+ .End()
+ .Export()
+ .Function("call_tbl0")
+ .Function("call_tbl1")
+ .Function("ret42")
+ .Function("ret1337")
+ .Function("ret256")
+ .End()
+ .Element()
+ .Element({tableIndex: 1, offset: 0, functionIndices: [2]})
+ .End()
+ .Code()
+ .Function("call_tbl0", { params: ["i32"], ret: "i32" })
+ .GetLocal(0)
+ .CallIndirect(1,0)
+ .End()
+
+ .Function("call_tbl1", { params: ["i32"], ret: "i32" })
+ .GetLocal(0)
+ .CallIndirect(1,1)
+ .End()
+
+ .Function("ret42", { params: [], ret: "i32" })
+ .I32Const(42)
+ .End()
+
+ .Function("ret1337", { params: [], ret: "i32" })
+ .I32Const(1337)
+ .End()
+
+ .Function("ret256", { params: [], ret: "i32" })
+ .I32Const(256)
+ .End()
+ .End().WebAssembly().get()));
+
+ fullGC()
+
+ assert.eq($1.exports.call_tbl1(0), 42)
+ assert.throws(() => $1.exports.call_tbl0(0), Error, "call_indirect to a null table entry (evaluating 'func(...args)')")
+ assert.throws(() => $1.exports.call_tbl1(1), Error, "call_indirect to a null table entry (evaluating 'func(...args)')")
+}
+
+{
+ const $1 = new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 30, element: "anyfunc"})
+ .Table({initial: 2, maximum: 30, element: "anyfunc"})
+ .End()
+ .Export()
+ .Function("call_tbl0")
+ .Function("call_tbl1")
+ .Function("ret42")
+ .Function("ret1337")
+ .Function("ret256")
+ .End()
+ .Element()
+ .Element({tableIndex: 1, offset: 0, functionIndices: [2]})
+ .Element({tableIndex: 0, offset: 0, functionIndices: [3]})
+ .Element({tableIndex: 1, offset: 1, functionIndices: [4]})
+ .End()
+ .Code()
+ .Function("call_tbl0", { params: ["i32"], ret: "i32" })
+ .GetLocal(0)
+ .CallIndirect(1,0)
+ .End()
+
+ .Function("call_tbl1", { params: ["i32"], ret: "i32" })
+ .GetLocal(0)
+ .CallIndirect(1,1)
+ .End()
+
+ .Function("ret42", { params: [], ret: "i32" })
+ .I32Const(42)
+ .End()
+
+ .Function("ret1337", { params: [], ret: "i32" })
+ .I32Const(1337)
+ .End()
+
+ .Function("ret256", { params: [], ret: "i32" })
+ .I32Const(256)
+ .End()
+ .End().WebAssembly().get()));
+
+ fullGC()
+
+ assert.eq($1.exports.call_tbl1(0), 42)
+ assert.eq($1.exports.call_tbl0(0), 1337)
+ assert.eq($1.exports.call_tbl1(1), 256)
+ assert.throws(() => $1.exports.call_tbl0(1), Error, "call_indirect to a null table entry (evaluating 'func(...args)')")
+ assert.throws(() => $1.exports.call_tbl0(2), Error, "call_indirect to a null table entry (evaluating 'func(...args)')")
+ assert.throws(() => $1.exports.call_tbl1(2), Error, "Out of bounds call_indirect (evaluating 'func(...args)')")
+}
+ assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyfunc"})
+ .Table({initial: 2, maximum: 2, element: "anyfunc"})
+ .End()
+ .Element()
+ .Element({tableIndex: 1, offset: 0, functionIndices: [0]})
+ .Element({tableIndex: 0, offset: 0, functionIndices: [0]})
+ .Element({tableIndex: 1, offset: 2, functionIndices: [0]})
+ .End()
+ .Code()
+ .Function("ret42", { params: [], ret: "i32" })
+ .I32Const(42)
+ .End()
+ .End().WebAssembly().get())), Error, "Element is trying to set an out of bounds table index (evaluating 'new WebAssembly.Instance')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Element()
+ .Element({tableIndex: 1, offset: 0, functionIndices: [0]})
+ .Element({tableIndex: 0, offset: 0, functionIndices: [0]})
+ .Element({tableIndex: 1, offset: 2, functionIndices: [0]})
+ .End()
+ .Code()
+ .Function("ret42", { params: [], ret: "i32" })
+ .I32Const(42)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 40: Table 0 must have type 'anyfunc' to have an element section (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(2)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't validate: table index 2 is invalid, limit is 2, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "void" })
+ .I32Const(0)
+ .RefNull()
+ .TableSet(2)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't validate: table index 2 is invalid, limit is 2, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "void" })
+ .CallIndirect(0, 2)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 4: call_indirect's table index 2 invalid, limit is 2, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "void" })
+ .CallIndirect(0,0)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 4: call_indirect is only valid when a table has type anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "void" })
+ .RefNull()
+ .TableGet(0)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't validate: table.get index to type Anyfunc expected I32, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: [], ret: "void" })
+ .RefNull()
+ .RefNull()
+ .TableSet(0)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't validate: table.set index to type Anyfunc expected I32, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module((new Builder())
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .Table({initial: 2, maximum: 3, element: "anyfunc"})
+ .End()
+ .Code()
+ .Function("fun", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't validate: table.set value to type Anyref expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module')")
+
+function tableInsanity(num, b) {
+ b = b.Import()
+ for (let i=0; i<100000-1; ++i)
+ b = b.Function("imp", "ref", { params: [], ret: "void" })
+ b = b.End().Function().End().Table()
+ for (let i=0; i<num; ++i)
+ b = b.Table({initial: 0, maximum: 3, element: "anyref"})
+ return b
+}
+
+assert.throws(() => new WebAssembly.Instance(new WebAssembly.Module(tableInsanity(1000000, (new Builder())
+ .Type().End())
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .End()
+ .Code()
+ .Function("fun", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1)
+ .End()
+ .End().WebAssembly().get())), Error, "WebAssembly.Module doesn't parse at byte 5000027: Table count of 1000000 is too big, maximum 1000000 (evaluating 'new WebAssembly.Module')")
+{
+ const $1 = new WebAssembly.Instance(new WebAssembly.Module(tableInsanity(1000000-2, (new Builder())
+ .Type().End())
+ .Table({initial: 3, maximum: 3, element: "anyfunc"})
+ .Table({initial: 3, maximum: 3, element: "anyref"})
+ .End()
+ .Export()
+ .Function("set_tbl")
+ .Function("get_tbl")
+ .Function("call")
+ .End()
+ .Element()
+ .Element({tableIndex: 1000000-2, offset: 0, functionIndices: [0]})
+ .End()
+ .Code()
+ .Function("set_tbl", { params: ["anyref"], ret: "void" })
+ .I32Const(0)
+ .GetLocal(0)
+ .TableSet(1000000-1)
+ .End()
+ .Function("get_tbl", { params: [], ret: "anyref" })
+ .I32Const(0)
+ .TableGet(1000000-1)
+ .End()
+ .Function("call", { params: [], ret: "void" })
+ .I32Const(0)
+ .CallIndirect(0, 1000000-2)
+ .End()
+ .End().WebAssembly().get()), { imp: { ref: function () {} } })
+ $1.exports.set_tbl("hi")
+ assert.eq($1.exports.get_tbl(), "hi")
+ $1.exports.call()
+}
Modified: trunk/JSTests/wasm/references/validation.js (246570 => 246571)
--- trunk/JSTests/wasm/references/validation.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/references/validation.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -24,6 +24,9 @@
{
const builder = (new Builder())
.Type().End()
+ .Import()
+ .Table("imp", "tbl", {initial: 2, element: "anyfunc"})
+ .End()
.Function().End()
.Export()
.Function("j")
@@ -32,7 +35,7 @@
.Function("j", { params: [], ret: "void" })
.I32Const(0)
.I32Const(0)
- .TableSet()
+ .TableSet(0)
.End()
.End();
@@ -39,7 +42,7 @@
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())')");
+ assert.throws(() => new WebAssembly.Module(bin.get()), WebAssembly.CompileError, "WebAssembly.Module doesn't validate: table.set value to type I32 expected Anyfunc, in function at index 0 (evaluating 'new WebAssembly.Module(bin.get())')");
}
{
@@ -56,7 +59,7 @@
.Function("j", { params: ["anyref"], ret: "void" })
.I32Const(0)
.GetLocal(0)
- .TableSet()
+ .TableSet(0)
.End()
.End();
@@ -79,7 +82,7 @@
.Code()
.Function("j", { params: [], ret: "anyref" })
.I32Const(0)
- .TableGet()
+ .TableGet(0)
.End()
.End();
Modified: trunk/JSTests/wasm/spec-tests/imports.wast.js (246570 => 246571)
--- trunk/JSTests/wasm/spec-tests/imports.wast.js 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/spec-tests/imports.wast.js 2019-06-18 22:01:02 UTC (rev 246571)
@@ -188,15 +188,6 @@
// imports.wast:290
assert_trap(() => call($14, "call", [100]));
-// imports.wast:293
-assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x8d\x80\x80\x80\x00\x02\x00\x00\x01\x70\x00\x0a\x00\x00\x01\x70\x00\x0a");
-
-// imports.wast:297
-assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x87\x80\x80\x80\x00\x01\x00\x00\x01\x70\x00\x0a\x04\x84\x80\x80\x80\x00\x01\x70\x00\x0a");
-
-// imports.wast:301
-assert_invalid("\x00\x61\x73\x6d\x01\x00\x00\x00\x04\x87\x80\x80\x80\x00\x02\x70\x00\x0a\x70\x00\x0a");
-
// imports.wast:306
let $15 = instance("\x00\x61\x73\x6d\x01\x00\x00\x00\x02\x97\x80\x80\x80\x00\x01\x04\x74\x65\x73\x74\x0c\x74\x61\x62\x6c\x65\x2d\x31\x30\x2d\x69\x6e\x66\x01\x70\x00\x0a");
Modified: trunk/JSTests/wasm/wasm.json (246570 => 246571)
--- trunk/JSTests/wasm/wasm.json 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/JSTests/wasm/wasm.json 2019-06-18 22:01:02 UTC (rev 246571)
@@ -67,10 +67,10 @@
"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" },
+ "table.get": { "category": "special", "value": 37, "return": ["anyref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" },
+ "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "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" },
+ "call_indirect": { "category": "call", "value": 17, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "type_index", "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"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" },
"i32.load8_u": { "category": "memory", "value": 45, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" },
"i32.load16_s": { "category": "memory", "value": 46, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" },
Modified: trunk/Source/_javascript_Core/ChangeLog (246570 => 246571)
--- trunk/Source/_javascript_Core/ChangeLog 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/ChangeLog 2019-06-18 22:01:02 UTC (rev 246571)
@@ -1,3 +1,66 @@
+2019-06-18 Justin Michaud <justin_mich...@apple.com>
+
+ [WASM-References] Add support for multiple tables
+ https://bugs.webkit.org/show_bug.cgi?id=198760
+
+ Reviewed by Saam Barati.
+
+ Support multiple wasm tables. We turn tableInformation into a tables array, and update all of the
+ existing users to give a table index. The array of Tables in Wasm::Instance is hung off the tail
+ to make it easier to use from jit code.
+
+ * wasm/WasmAirIRGenerator.cpp:
+ (JSC::Wasm::AirIRGenerator::AirIRGenerator):
+ (JSC::Wasm::AirIRGenerator::addTableGet):
+ (JSC::Wasm::AirIRGenerator::addTableSet):
+ (JSC::Wasm::AirIRGenerator::addCallIndirect):
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+ (JSC::Wasm::B3IRGenerator::addTableGet):
+ (JSC::Wasm::B3IRGenerator::addTableSet):
+ (JSC::Wasm::B3IRGenerator::addCallIndirect):
+ * wasm/WasmExceptionType.h:
+ * wasm/WasmFormat.h:
+ (JSC::Wasm::Element::Element):
+ * wasm/WasmFunctionParser.h:
+ (JSC::Wasm::FunctionParser<Context>::parseExpression):
+ (JSC::Wasm::FunctionParser<Context>::parseUnreachableExpression):
+ * wasm/WasmInstance.cpp:
+ (JSC::Wasm::Instance::Instance):
+ (JSC::Wasm::Instance::create):
+ (JSC::Wasm::Instance::extraMemoryAllocated const):
+ (JSC::Wasm::Instance::table):
+ (JSC::Wasm::Instance::setTable):
+ * wasm/WasmInstance.h:
+ (JSC::Wasm::Instance::updateCachedMemory):
+ (JSC::Wasm::Instance::offsetOfGlobals):
+ (JSC::Wasm::Instance::offsetOfTablePtr):
+ (JSC::Wasm::Instance::allocationSize):
+ (JSC::Wasm::Instance::table): Deleted.
+ (JSC::Wasm::Instance::setTable): Deleted.
+ (JSC::Wasm::Instance::offsetOfTable): Deleted.
+ * wasm/WasmModuleInformation.h:
+ (JSC::Wasm::ModuleInformation::tableCount const):
+ * wasm/WasmSectionParser.cpp:
+ (JSC::Wasm::SectionParser::parseImport):
+ (JSC::Wasm::SectionParser::parseTableHelper):
+ (JSC::Wasm::SectionParser::parseTable):
+ (JSC::Wasm::SectionParser::parseElement):
+ * wasm/WasmTable.h:
+ (JSC::Wasm::Table::owner const):
+ * wasm/WasmValidate.cpp:
+ (JSC::Wasm::Validate::addTableGet):
+ (JSC::Wasm::Validate::addTableSet):
+ (JSC::Wasm::Validate::addCallIndirect):
+ * wasm/js/JSWebAssemblyInstance.cpp:
+ (JSC::JSWebAssemblyInstance::JSWebAssemblyInstance):
+ (JSC::JSWebAssemblyInstance::visitChildren):
+ * wasm/js/JSWebAssemblyInstance.h:
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::link):
+ (JSC::WebAssemblyModuleRecord::evaluate):
+ * wasm/wasm.json:
+
2019-06-18 Alexey Shvayka <shvaikal...@gmail.com>
[ESNExt] String.prototype.matchAll
Modified: trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmAirIRGenerator.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -237,8 +237,8 @@
PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
// Tables
- PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
- PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
+ PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
// Locals
PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -277,7 +277,7 @@
// Calls
PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
- PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
PartialResult WARN_UNUSED_RETURN addUnreachable();
PartialResult addShift(Type, B3::Air::Opcode, ExpressionType value, ExpressionType shift, ExpressionType& result);
@@ -626,6 +626,7 @@
}
uint32_t m_maxNumJSCallArguments { 0 };
+ unsigned m_numImportFunctions;
B3::PatchpointSpecial* m_patchpointSpecial { nullptr };
};
@@ -681,6 +682,7 @@
, m_proc(procedure)
, m_code(m_proc.code())
, m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
+ , m_numImportFunctions(info.importFunctionCount())
{
m_currentBlock = m_code.addBlock();
m_rootBlock = m_currentBlock;
@@ -968,7 +970,7 @@
return { };
}
-auto AirIRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
{
// FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
ASSERT(index.tmp());
@@ -975,7 +977,7 @@
ASSERT(index.type() == Type::I32);
result = tmpForType(Type::Anyref);
- emitCCall(&getWasmTableElement, result, instanceValue(), index);
+ emitCCall(&getWasmTableElement, result, instanceValue(), addConstant(Type::I32, tableIndex), index);
emitCheck([&] {
return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), result, result);
}, [=] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
@@ -985,7 +987,7 @@
return { };
}
-auto AirIRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
+auto AirIRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
{
// FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
ASSERT(index.tmp());
@@ -993,7 +995,7 @@
ASSERT(value.tmp());
auto shouldThrow = g32();
- emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), index, value);
+ emitCCall(&setWasmTableElement, shouldThrow, instanceValue(), addConstant(Type::I32, tableIndex), index, value);
emitCheck([&] {
return Inst(BranchTest32, nullptr, Arg::resCond(MacroAssembler::Zero), shouldThrow, shouldThrow);
@@ -1893,11 +1895,12 @@
return { };
}
-auto AirIRGenerator::addCallIndirect(const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
+auto AirIRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
{
ExpressionType calleeIndex = args.takeLast();
ASSERT(signature.argumentCount() == args.size());
- ASSERT(m_info.tableInformation.type() == TableElementType::Funcref);
+ ASSERT(m_info.tableCount() > tableIndex);
+ ASSERT(m_info.tables[tableIndex].type() == TableElementType::Funcref);
m_makesCalls = true;
// Note: call indirect can call either WebAssemblyFunction or WebAssemblyWrapperFunction. Because
@@ -1912,12 +1915,16 @@
ExpressionType instancesBuffer = g64();
ExpressionType callableFunctionBufferLength = g64();
{
- RELEASE_ASSERT(Arg::isValidAddrForm(Instance::offsetOfTable(), 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);
+ if (UNLIKELY(!Arg::isValidAddrForm(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex), B3::Width64))) {
+ append(Move, Arg::bigImm(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)), callableFunctionBufferLength);
+ append(Add64, instanceValue(), callableFunctionBufferLength);
+ append(Move, Arg::addr(callableFunctionBufferLength), callableFunctionBufferLength);
+ } else
+ append(Move, Arg::addr(instanceValue(), Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)), callableFunctionBufferLength);
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 (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -190,8 +190,8 @@
PartialResult WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
// Tables
- PartialResult WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
- PartialResult WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
+ PartialResult WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
// Locals
PartialResult WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -230,7 +230,7 @@
// Calls
PartialResult WARN_UNUSED_RETURN addCall(uint32_t calleeIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
- PartialResult WARN_UNUSED_RETURN addCallIndirect(const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
+ PartialResult WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, Vector<ExpressionType>& args, ExpressionType& result);
PartialResult WARN_UNUSED_RETURN addUnreachable();
void dump(const Vector<ControlEntry>& controlStack, const ExpressionList* expressionStack);
@@ -292,6 +292,7 @@
}
uint32_t m_maxNumJSCallArguments { 0 };
+ unsigned m_numImportFunctions;
};
// Memory accesses in WebAssembly have unsigned 32-bit offsets, whereas they have signed 32-bit offsets in B3.
@@ -343,6 +344,7 @@
, m_proc(procedure)
, m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
, m_constantInsertionValues(m_proc)
+ , m_numImportFunctions(info.importFunctionCount())
{
m_currentBlock = m_proc.addBlock();
@@ -566,12 +568,12 @@
return { };
}
-auto B3IRGenerator::addTableGet(ExpressionType& index, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> PartialResult
{
// FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
result = m_currentBlock->appendNew<CCallValue>(m_proc, toB3Type(Anyref), origin(),
m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&getWasmTableElement, B3CCallPtrTag)),
- instanceValue(), index);
+ instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), index);
{
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
@@ -585,12 +587,12 @@
return { };
}
-auto B3IRGenerator::addTableSet(ExpressionType& index, ExpressionType& value) -> PartialResult
+auto B3IRGenerator::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> PartialResult
{
// FIXME: Emit this inline <https://bugs.webkit.org/show_bug.cgi?id=198506>.
auto shouldThrow = m_currentBlock->appendNew<CCallValue>(m_proc, B3::Int32, origin(),
m_currentBlock->appendNew<ConstPtrValue>(m_proc, origin(), tagCFunctionPtr<void*>(&setWasmTableElement, B3CCallPtrTag)),
- instanceValue(), index, value);
+ instanceValue(), m_currentBlock->appendNew<Const32Value>(m_proc, origin(), tableIndex), index, value);
{
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, origin(),
@@ -1298,7 +1300,7 @@
return { };
}
-auto B3IRGenerator::addCallIndirect(const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
+auto B3IRGenerator::addCallIndirect(unsigned tableIndex, const Signature& signature, Vector<ExpressionType>& args, ExpressionType& result) -> PartialResult
{
ExpressionType calleeIndex = args.takeLast();
ASSERT(signature.argumentCount() == args.size());
@@ -1315,7 +1317,7 @@
ExpressionType mask;
{
ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
- instanceValue(), safeCast<int32_t>(Instance::offsetOfTable()));
+ instanceValue(), safeCast<int32_t>(Instance::offsetOfTablePtr(m_numImportFunctions, tableIndex)));
callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
table, safeCast<int32_t>(FuncRefTable::offsetOfFunctions()));
instancesBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), origin(),
Modified: trunk/Source/_javascript_Core/wasm/WasmFormat.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmFormat.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmFormat.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -213,10 +213,12 @@
};
struct Element {
- Element(I32InitExpr offset)
- : offset(offset)
+ Element(uint32_t tableIndex, I32InitExpr offset)
+ : tableIndex(tableIndex)
+ , offset(offset)
{ }
+ uint32_t tableIndex;
I32InitExpr offset;
Vector<uint32_t> functionIndices;
};
Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -283,9 +283,11 @@
case TableGet: {
WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ unsigned tableIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
ExpressionType result, index;
WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.get");
- WASM_TRY_ADD_TO_CONTEXT(addTableGet(index, result));
+ WASM_TRY_ADD_TO_CONTEXT(addTableGet(tableIndex, index, result));
m_expressionStack.append(result);
return { };
}
@@ -292,10 +294,12 @@
case TableSet: {
WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
+ unsigned tableIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
ExpressionType val, index;
WASM_TRY_POP_EXPRESSION_STACK_INTO(val, "table.set");
WASM_TRY_POP_EXPRESSION_STACK_INTO(index, "table.set");
- WASM_TRY_ADD_TO_CONTEXT(addTableSet(index, val));
+ WASM_TRY_ADD_TO_CONTEXT(addTableSet(tableIndex, index, val));
return { };
}
@@ -396,13 +400,13 @@
case CallIndirect: {
uint32_t signatureIndex;
- uint8_t reserved;
- WASM_PARSER_FAIL_IF(!m_info.tableInformation, "call_indirect is only valid when a table is defined or imported");
+ uint32_t tableIndex;
+ WASM_PARSER_FAIL_IF(!m_info.tableCount(), "call_indirect is only valid when a table is defined or imported");
WASM_PARSER_FAIL_IF(!parseVarUInt32(signatureIndex), "can't get call_indirect's signature index");
- 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(!parseVarUInt32(tableIndex), "can't get call_indirect's table index");
+ WASM_PARSER_FAIL_IF(tableIndex >= m_info.tableCount(), "call_indirect's table index ", tableIndex, " invalid, limit is ", m_info.tableCount());
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");
+ WASM_PARSER_FAIL_IF(m_info.tables[tableIndex].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.
@@ -416,7 +420,7 @@
m_expressionStack.shrink(firstArgumentIndex);
ExpressionType result = Context::emptyExpression();
- WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(calleeSignature, args, result));
+ WASM_TRY_ADD_TO_CONTEXT(addCallIndirect(tableIndex, calleeSignature, args, result));
if (result != Context::emptyExpression())
m_expressionStack.append(result);
@@ -631,9 +635,9 @@
case CallIndirect: {
uint32_t unused;
- uint8_t unused2;
+ uint32_t unused2;
WASM_PARSER_FAIL_IF(!parseVarUInt32(unused), "can't get call_indirect's signature index in unreachable context");
- WASM_PARSER_FAIL_IF(!parseVarUInt1(unused2), "can't get call_indirect's reserved byte in unreachable context");
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(unused2), "can't get call_indirect's reserved byte in unreachable context");
return { };
}
@@ -685,7 +689,11 @@
}
case TableGet:
- case TableSet:
+ case TableSet: {
+ unsigned tableIndex;
+ WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't parse table index");
+ FALLTHROUGH;
+ }
case RefIsNull:
case RefNull: {
WASM_PARSER_FAIL_IF(!Options::useWebAssemblyReferences(), "references are not enabled");
Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmInstance.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -61,11 +61,12 @@
if (isSubtype(m_module.get().moduleInformation().globals[i].type, Anyref))
m_globalsToMark.set(i);
}
+ memset(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, 0), 0, m_module->moduleInformation().tableCount() * sizeof(Table*));
}
Ref<Instance> Instance::create(Context* context, Ref<Module>&& module, EntryFrame** pointerToTopEntryFrame, void** pointerToActualStackLimit, StoreTopCallFrameCallback&& storeTopCallFrame)
{
- return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount()))) Instance(context, WTFMove(module), pointerToTopEntryFrame, pointerToActualStackLimit, WTFMove(storeTopCallFrame)));
+ return adoptRef(*new (NotNull, fastMalloc(allocationSize(module->moduleInformation().importFunctionCount(), module->moduleInformation().tableCount()))) Instance(context, WTFMove(module), pointerToTopEntryFrame, pointerToActualStackLimit, WTFMove(storeTopCallFrame)));
}
Instance::~Instance() { }
@@ -72,7 +73,7 @@
size_t Instance::extraMemoryAllocated() const
{
- return globalMemoryByteSize(m_module.get()) + allocationSize(m_numImportFunctions);
+ return globalMemoryByteSize(m_module.get()) + allocationSize(m_numImportFunctions, m_module->moduleInformation().tableCount());
}
void Instance::setGlobal(unsigned i, JSValue value)
@@ -99,31 +100,46 @@
ASSERT(getFunctionWrapper(i) == value);
}
-EncodedJSValue getWasmTableElement(Instance* instance, int32_t signedIndex)
+Table* Instance::table(unsigned i)
{
+ RELEASE_ASSERT(i < m_module->moduleInformation().tableCount());
+ return *bitwise_cast<Table**>(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, i));
+}
+
+void Instance::setTable(unsigned i, Ref<Table>&& table)
+{
+ RELEASE_ASSERT(i < m_module->moduleInformation().tableCount());
+ ASSERT(!this->table(i));
+ *bitwise_cast<Table**>(bitwise_cast<char*>(this) + offsetOfTablePtr(m_numImportFunctions, i)) = &table.leakRef();
+}
+
+EncodedJSValue getWasmTableElement(Instance* instance, unsigned tableIndex, int32_t signedIndex)
+{
+ ASSERT(tableIndex < instance->module().moduleInformation().tableCount());
if (signedIndex < 0)
return 0;
uint32_t index = signedIndex;
- if (index >= instance->table()->length())
+ if (index >= instance->table(tableIndex)->length())
return 0;
- return JSValue::encode(instance->table()->get(index));
+ return JSValue::encode(instance->table(tableIndex)->get(index));
}
-bool setWasmTableElement(Instance* instance, int32_t signedIndex, EncodedJSValue encValue)
+bool setWasmTableElement(Instance* instance, unsigned tableIndex, int32_t signedIndex, EncodedJSValue encValue)
{
+ ASSERT(tableIndex < instance->module().moduleInformation().tableCount());
if (signedIndex < 0)
return false;
uint32_t index = signedIndex;
- if (index >= instance->table()->length())
+ if (index >= instance->table(tableIndex)->length())
return false;
JSValue value = JSValue::decode(encValue);
- if (instance->table()->type() == Wasm::TableElementType::Anyref)
- instance->table()->set(index, value);
- else if (instance->table()->type() == Wasm::TableElementType::Funcref) {
+ if (instance->table(tableIndex)->type() == Wasm::TableElementType::Anyref)
+ instance->table(tableIndex)->set(index, value);
+ else if (instance->table(tableIndex)->type() == Wasm::TableElementType::Funcref) {
WebAssemblyFunction* wasmFunction;
WebAssemblyWrapperFunction* wasmWrapperFunction;
@@ -130,11 +146,11 @@
if (isWebAssemblyHostFunction(*instance->owner<JSObject>()->vm(), value, wasmFunction, wasmWrapperFunction)) {
ASSERT(!!wasmFunction || !!wasmWrapperFunction);
if (wasmFunction)
- instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
+ instance->table(tableIndex)->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmFunction->importableFunction(), &wasmFunction->instance()->instance());
else
- instance->table()->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
+ instance->table(tableIndex)->asFuncrefTable()->setFunction(index, jsCast<JSObject*>(value), wasmWrapperFunction->importableFunction(), &wasmWrapperFunction->instance()->instance());
} else if (value.isNull())
- instance->table()->clear(index);
+ instance->table(tableIndex)->clear(index);
else
ASSERT_NOT_REACHED();
} else
Modified: trunk/Source/_javascript_Core/wasm/WasmInstance.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmInstance.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmInstance.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -41,8 +41,8 @@
struct Context;
class Instance;
-EncodedJSValue getWasmTableElement(Instance*, int32_t);
-bool setWasmTableElement(Instance*, int32_t, EncodedJSValue encValue);
+EncodedJSValue getWasmTableElement(Instance*, unsigned, int32_t);
+bool setWasmTableElement(Instance*, unsigned, int32_t, EncodedJSValue encValue);
EncodedJSValue doWasmRefFunc(Instance*, uint32_t);
class Instance : public ThreadSafeRefCounted<Instance>, public CanMakeWeakPtr<Instance> {
@@ -70,7 +70,8 @@
Module& module() { return m_module.get(); }
CodeBlock* codeBlock() { return m_codeBlock.get(); }
Memory* memory() { return m_memory.get(); }
- Table* table() { return m_table.get(); }
+ Table* table(unsigned);
+ void setTable(unsigned, Ref<Table>&&);
void* cachedMemory() const { return m_cachedMemory.getMayBeNull(cachedMemorySize()); }
size_t cachedMemorySize() const { return m_cachedMemorySize; }
@@ -88,7 +89,6 @@
m_cachedMemorySize = memory()->size();
}
}
- void setTable(Ref<Table>&& table) { m_table = WTFMove(table); }
int32_t loadI32Global(unsigned i) const { return m_globals.get()[i].primitive; }
int64_t loadI64Global(unsigned i) const { return m_globals.get()[i].primitive; }
@@ -103,7 +103,6 @@
static ptrdiff_t offsetOfMemory() { return OBJECT_OFFSETOF(Instance, m_memory); }
static ptrdiff_t offsetOfGlobals() { return OBJECT_OFFSETOF(Instance, m_globals); }
- static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(Instance, m_table); }
static ptrdiff_t offsetOfCachedMemory() { return OBJECT_OFFSETOF(Instance, m_cachedMemory); }
static ptrdiff_t offsetOfCachedMemorySize() { return OBJECT_OFFSETOF(Instance, m_cachedMemorySize); }
static ptrdiff_t offsetOfPointerToTopEntryFrame() { return OBJECT_OFFSETOF(Instance, m_pointerToTopEntryFrame); }
@@ -122,7 +121,7 @@
}
// Tail accessors.
- static size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
+ static constexpr size_t offsetOfTail() { return WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(Instance)); }
struct ImportFunctionInfo {
// Target instance and entrypoint are only set for wasm->wasm calls, and are otherwise nullptr. The embedder-specific logic occurs through import function.
Instance* targetInstance { nullptr };
@@ -142,6 +141,9 @@
static size_t offsetOfImportFunction(size_t importFunctionNum) { return offsetOfTail() + importFunctionNum * sizeof(ImportFunctionInfo) + OBJECT_OFFSETOF(ImportFunctionInfo, importFunction); }
template<typename T> T* importFunction(unsigned importFunctionNum) { return reinterpret_cast<T*>(&importFunctionInfo(importFunctionNum)->importFunction); }
+ static_assert(sizeof(ImportFunctionInfo) == WTF::roundUpToMultipleOf<sizeof(uint64_t)>(sizeof(ImportFunctionInfo)), "We rely on this for the alignment to be correct");
+ static constexpr size_t offsetOfTablePtr(unsigned numImportFunctions, unsigned i) { return offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions + sizeof(Table*) * i; }
+
void storeTopCallFrame(void* callFrame)
{
m_storeTopCallFrame(callFrame);
@@ -150,9 +152,9 @@
private:
Instance(Context*, Ref<Module>&&, EntryFrame**, void**, StoreTopCallFrameCallback&&);
- static size_t allocationSize(Checked<size_t> numImportFunctions)
+ static size_t allocationSize(Checked<size_t> numImportFunctions, Checked<size_t> numTables)
{
- return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions).unsafeGet();
+ return (offsetOfTail() + sizeof(ImportFunctionInfo) * numImportFunctions + sizeof(Table*) * numTables).unsafeGet();
}
void* m_owner { nullptr }; // In a JS embedding, this is a JSWebAssemblyInstance*.
Context* m_context { nullptr };
@@ -161,7 +163,6 @@
Ref<Module> m_module;
RefPtr<CodeBlock> m_codeBlock;
RefPtr<Memory> m_memory;
- RefPtr<Table> m_table;
union GlobalValue {
WriteBarrier<Unknown> anyref;
Modified: trunk/Source/_javascript_Core/wasm/WasmLimits.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmLimits.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmLimits.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -51,6 +51,7 @@
constexpr size_t maxFunctionParams = 1000;
constexpr size_t maxTableEntries = 10000000;
+constexpr unsigned maxTables = 1000000;
} } // namespace JSC::Wasm
Modified: trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmModuleInformation.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -65,7 +65,7 @@
// Currently, our wasm implementation allows only one memory and table.
// If we need to remove this limitation, we would have MemoryInformation and TableInformation in the Vectors.
uint32_t memoryCount() const { return memory ? 1 : 0; }
- uint32_t tableCount() const { return tableInformation ? 1 : 0; }
+ uint32_t tableCount() const { return tables.size(); }
const BitVector& referencedFunctions() const { return m_referencedFunctions; }
void addReferencedFunction(unsigned index) const { m_referencedFunctions.set(index); }
@@ -83,7 +83,7 @@
Optional<uint32_t> startFunctionIndexSpace;
Vector<Segment::Ptr> data;
Vector<Element> elements;
- TableInformation tableInformation;
+ Vector<TableInformation> tables;
Vector<Global> globals;
unsigned firstInternalGlobal { 0 };
Vector<CustomSection> customSections;
Modified: trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmSectionParser.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -119,6 +119,7 @@
}
case ExternalKind::Table: {
bool isImport = true;
+ kindIndex = m_info->tables.size();
PartialResult result = parseTableHelper(isImport);
if (UNLIKELY(!result))
return makeUnexpected(WTFMove(result.error()));
@@ -193,7 +194,7 @@
auto SectionParser::parseTableHelper(bool isImport) -> PartialResult
{
- WASM_PARSER_FAIL_IF(m_info->tableCount() > 0, "Cannot have more than one Table for now");
+ WASM_PARSER_FAIL_IF(m_info->tableCount() >= maxTables, "Table count of ", m_info->tableCount(), " is too big, maximum ", maxTables);
int8_t type;
WASM_PARSER_FAIL_IF(!parseInt7(type), "can't parse Table type");
@@ -209,7 +210,7 @@
ASSERT(!maximum || *maximum >= initial);
TableElementType tableType = type == Wasm::Anyfunc ? TableElementType::Funcref : TableElementType::Anyref;
- m_info->tableInformation = TableInformation(initial, maximum, isImport, tableType);
+ m_info->tables.append(TableInformation(initial, maximum, isImport, tableType));
return { };
}
@@ -218,16 +219,14 @@
{
uint32_t count;
WASM_PARSER_FAIL_IF(!parseVarUInt32(count), "can't get Table's count");
- WASM_PARSER_FAIL_IF(count > 1, "Table count of ", count, " is invalid, at most 1 is allowed for now");
- if (!count)
- return { };
+ for (unsigned i = 0; i < count; ++i) {
+ bool isImport = false;
+ PartialResult result = parseTableHelper(isImport);
+ if (UNLIKELY(!result))
+ return makeUnexpected(WTFMove(result.error()));
+ }
- bool isImport = false;
- PartialResult result = parseTableHelper(isImport);
- if (UNLIKELY(!result))
- return makeUnexpected(WTFMove(result.error()));
-
return { };
}
@@ -379,7 +378,7 @@
WASM_PARSER_FAIL_IF(!parseVarUInt32(tableIndex), "can't get ", elementNum, "th Element table index");
WASM_PARSER_FAIL_IF(tableIndex >= m_info->tableCount(), "Element section for Table ", tableIndex, " exceeds available Table ", m_info->tableCount());
- WASM_PARSER_FAIL_IF(m_info->tableInformation.type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'anyfunc' to have an element section");
+ WASM_PARSER_FAIL_IF(m_info->tables[tableIndex].type() != TableElementType::Funcref, "Table ", tableIndex, " must have type 'anyfunc' to have an element section");
Type initExprType;
WASM_FAIL_IF_HELPER_FAILS(parseInitExpr(initOpcode, initExprBits, initExprType));
WASM_PARSER_FAIL_IF(initExprType != I32, "Element init_expr must produce an i32");
@@ -386,9 +385,9 @@
WASM_PARSER_FAIL_IF(!parseVarUInt32(indexCount), "can't get ", elementNum, "th index count for Element section");
WASM_PARSER_FAIL_IF(indexCount == std::numeric_limits<uint32_t>::max(), "Element section's ", elementNum, "th index count is too big ", indexCount);
- ASSERT(!!m_info->tableInformation);
+ ASSERT(!!m_info->tables[tableIndex]);
- Element element(makeI32InitExpr(initOpcode, initExprBits));
+ Element element(tableIndex, makeI32InitExpr(initOpcode, initExprBits));
WASM_PARSER_FAIL_IF(!element.functionIndices.tryReserveCapacity(indexCount), "can't allocate memory for ", indexCount, " Element indices");
for (unsigned index = 0; index < indexCount; ++index) {
Modified: trunk/Source/_javascript_Core/wasm/WasmTable.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmTable.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmTable.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -57,6 +57,7 @@
static uint32_t allocatedLength(uint32_t length);
uint32_t mask() const { return m_mask; }
+ template<typename T> T* owner() const { return reinterpret_cast<T*>(m_owner); }
void setOwner(JSObject* owner)
{
ASSERT(!m_owner);
Modified: trunk/Source/_javascript_Core/wasm/WasmValidate.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/WasmValidate.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/WasmValidate.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -106,8 +106,8 @@
Result WARN_UNUSED_RETURN addRefFunc(uint32_t index, ExpressionType& result);
// Tables
- Result WARN_UNUSED_RETURN addTableGet(ExpressionType& index, ExpressionType& result);
- Result WARN_UNUSED_RETURN addTableSet(ExpressionType& index, ExpressionType& value);
+ Result WARN_UNUSED_RETURN addTableGet(unsigned, ExpressionType& index, ExpressionType& result);
+ Result WARN_UNUSED_RETURN addTableSet(unsigned, ExpressionType& index, ExpressionType& value);
// Locals
Result WARN_UNUSED_RETURN getLocal(uint32_t index, ExpressionType& result);
@@ -148,7 +148,7 @@
// Calls
Result WARN_UNUSED_RETURN addCall(unsigned calleeIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
- Result WARN_UNUSED_RETURN addCallIndirect(const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
+ Result WARN_UNUSED_RETURN addCallIndirect(unsigned tableIndex, const Signature&, const Vector<ExpressionType>& args, ExpressionType& result);
ALWAYS_INLINE void didKill(ExpressionType) { }
@@ -178,21 +178,22 @@
return { };
}
-auto Validate::addTableGet(ExpressionType& index, ExpressionType& result) -> Result
+auto Validate::addTableGet(unsigned tableIndex, ExpressionType& index, ExpressionType& result) -> Result
{
- result = m_module.tableInformation.wasmType();
+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
+ result = m_module.tables[tableIndex].wasmType();
WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.get index to type ", index, " expected ", Type::I32);
return { };
}
-auto Validate::addTableSet(ExpressionType& index, ExpressionType& value) -> Result
+auto Validate::addTableSet(unsigned tableIndex, ExpressionType& index, ExpressionType& value) -> Result
{
- auto type = m_module.tableInformation.wasmType();
+ WASM_VALIDATOR_FAIL_IF(tableIndex >= m_module.tableCount(), "table index ", tableIndex, " is invalid, limit is ", m_module.tableCount());
+ auto type = m_module.tables[tableIndex].wasmType();
WASM_VALIDATOR_FAIL_IF(Type::I32 != index, "table.set index to type ", index, " expected ", Type::I32);
WASM_VALIDATOR_FAIL_IF(!isSubtype(value, type), "table.set value to type ", value, " expected ", type);
- WASM_VALIDATOR_FAIL_IF(m_module.tableInformation.type() != TableElementType::Anyref
- && m_module.tableInformation.type() != TableElementType::Funcref, "table.set expects the table to have type anyref or anyfunc");
+ RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Anyref || m_module.tables[tableIndex].type() == TableElementType::Funcref);
return { };
}
@@ -379,9 +380,10 @@
return { };
}
-auto Validate::addCallIndirect(const Signature& signature, const Vector<ExpressionType>& args, ExpressionType& result) -> Result
+auto Validate::addCallIndirect(unsigned tableIndex, 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");
+ RELEASE_ASSERT(tableIndex < m_module.tableCount());
+ RELEASE_ASSERT(m_module.tables[tableIndex].type() == TableElementType::Funcref);
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/JSWebAssemblyInstance.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -53,6 +53,7 @@
: Base(vm, structure)
, m_instance(WTFMove(instance))
, m_vm(&vm)
+ , m_tables(m_instance->module().moduleInformation().tableCount())
{
for (unsigned i = 0; i < this->instance().numImportFunctions(); ++i)
new (this->instance().importFunction<WriteBarrier<JSObject>>(i)) WriteBarrier<JSObject>();
@@ -85,7 +86,8 @@
visitor.append(thisObject->m_codeBlock);
visitor.append(thisObject->m_moduleNamespaceObject);
visitor.append(thisObject->m_memory);
- visitor.append(thisObject->m_table);
+ for (unsigned i = 0; i < thisObject->instance().module().moduleInformation().tableCount(); ++i)
+ visitor.append(thisObject->m_tables[i]);
visitor.append(thisObject->m_callee);
visitor.reportExtraMemoryVisited(thisObject->m_instance->extraMemoryAllocated());
for (unsigned i = 0; i < thisObject->instance().numImportFunctions(); ++i)
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h 2019-06-18 22:01:02 UTC (rev 246571)
@@ -71,11 +71,13 @@
}
Wasm::MemoryMode memoryMode() { return memory()->memory().mode(); }
- JSWebAssemblyTable* table() { return m_table.get(); }
- void setTable(VM& vm, JSWebAssemblyTable* value) {
- ASSERT(!table());
- m_table.set(vm, this, value);
- instance().setTable(makeRef(*table()->table()));
+ JSWebAssemblyTable* table(unsigned i) { return m_tables[i].get(); }
+ void setTable(VM& vm, uint32_t index, JSWebAssemblyTable* value)
+ {
+ ASSERT(index < m_tables.size());
+ ASSERT(!table(index));
+ m_tables[index].set(vm, this, value);
+ instance().setTable(index, makeRef(*table(index)->table()));
}
JSWebAssemblyModule* module() const { return m_module.get(); }
@@ -98,7 +100,7 @@
WriteBarrier<JSWebAssemblyCodeBlock> m_codeBlock;
WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
WriteBarrier<JSWebAssemblyMemory> m_memory;
- WriteBarrier<JSWebAssemblyTable> m_table;
+ Vector<WriteBarrier<JSWebAssemblyTable>> m_tables;
WriteBarrier<WebAssemblyToJSCallee> m_callee;
};
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp 2019-06-18 22:01:02 UTC (rev 246571)
@@ -113,8 +113,6 @@
return makeString(before, " ", String::fromUTF8(import.module), ":", String::fromUTF8(import.field), " ", after);
};
- bool hasTableImport = false;
-
for (const auto& import : moduleInformation.imports) {
// Validation and linking other than Wasm::ExternalKind::Function is already done in JSWebAssemblyInstance.
// Eventually we will move all the linking code in JSWebAssemblyInstance here and remove this switch statement.
@@ -264,20 +262,18 @@
}
case Wasm::ExternalKind::Table: {
- RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
// 7. Otherwise (i is a table import):
- hasTableImport = true;
JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(vm, value);
// i. If v is not a WebAssembly.Table object, throw a WebAssembly.LinkError.
if (!table)
return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "is not an instance of WebAssembly.Table")));
- uint32_t expectedInitial = moduleInformation.tableInformation.initial();
+ uint32_t expectedInitial = moduleInformation.tables[import.kindIndex].initial();
uint32_t actualInitial = table->length();
if (actualInitial < expectedInitial)
return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided an 'initial' that is too small")));
- if (Optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
+ if (Optional<uint32_t> expectedMaximum = moduleInformation.tables[import.kindIndex].maximum()) {
Optional<uint32_t> actualMaximum = table->maximum();
if (!actualMaximum)
return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "does not have a 'maximum' but the module requires that it does")));
@@ -285,7 +281,7 @@
return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Imported Table", "'maximum' is larger than the module's expected 'maximum'")));
}
- auto expectedType = moduleInformation.tableInformation.type();
+ auto expectedType = moduleInformation.tables[import.kindIndex].type();
auto actualType = table->table()->type();
if (expectedType != actualType)
return exception(createJSWebAssemblyLinkError(exec, vm, importFailMessage(import, "Table import", "provided a 'type' that is wrong")));
@@ -292,7 +288,7 @@
// ii. Append v to tables.
// iii. Append v.[[Table]] to imports.
- m_instance->setTable(vm, table);
+ m_instance->setTable(vm, import.kindIndex, table);
RETURN_IF_EXCEPTION(scope, void());
break;
}
@@ -302,16 +298,16 @@
}
}
- {
- if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
+ for (unsigned i = 0; i < moduleInformation.tableCount(); ++i) {
+ if (moduleInformation.tables[i].isImport()) {
// We should either have a Table import or we should have thrown an exception.
- RELEASE_ASSERT(hasTableImport);
+ RELEASE_ASSERT(m_instance->table(i));
}
- if (!!moduleInformation.tableInformation && !hasTableImport) {
- RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
+ if (!m_instance->table(i)) {
+ RELEASE_ASSERT(!moduleInformation.tables[i].isImport());
// We create a Table when it's a Table definition.
- RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum(), moduleInformation.tableInformation.type());
+ RefPtr<Wasm::Table> wasmTable = Wasm::Table::tryCreate(moduleInformation.tables[i].initial(), moduleInformation.tables[i].maximum(), moduleInformation.tables[i].type());
if (!wasmTable)
return exception(createJSWebAssemblyLinkError(exec, vm, "couldn't create Table"));
JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, globalObject->webAssemblyTableStructure(), wasmTable.releaseNonNull());
@@ -319,7 +315,7 @@
// If it's defined to be too large, we should have thrown a validation error.
scope.assertNoException();
ASSERT(table);
- m_instance->setTable(vm, table);
+ m_instance->setTable(vm, i, table);
RETURN_IF_EXCEPTION(scope, void());
}
}
@@ -397,10 +393,8 @@
}
case Wasm::ExternalKind::Table: {
// This should be guaranteed by module verification.
- RELEASE_ASSERT(m_instance->table());
- ASSERT(exp.kindIndex == 0);
-
- exportedValue = m_instance->table();
+ RELEASE_ASSERT(m_instance->table(exp.kindIndex));
+ exportedValue = m_instance->table(exp.kindIndex);
break;
}
case Wasm::ExternalKind::Memory: {
@@ -486,7 +480,6 @@
Wasm::Module& module = m_instance->instance().module();
Wasm::CodeBlock* codeBlock = m_instance->instance().codeBlock();
const Wasm::ModuleInformation& moduleInformation = module.moduleInformation();
- JSWebAssemblyTable* table = m_instance->table();
const Vector<Wasm::Segment::Ptr>& data = ""
@@ -498,16 +491,16 @@
// Also, it could be that a table wasn't imported, or that the table
// imported wasn't compatible. However, those should error out before
// getting here.
- ASSERT(!!table);
+ ASSERT(!!m_instance->table(element.tableIndex));
if (!element.functionIndices.size())
continue;
- uint32_t tableIndex = element.offset.isGlobalImport()
+ uint32_t elementIndex = element.offset.isGlobalImport()
? static_cast<uint32_t>(m_instance->instance().loadI32Global(element.offset.globalImportIndex()))
: element.offset.constValue();
- fn(element, tableIndex);
+ fn(element, element.tableIndex, elementIndex);
if (exception)
break;
@@ -531,9 +524,9 @@
};
// Validation of all element ranges comes before all Table and Memory initialization.
- forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
- uint64_t lastWrittenIndex = static_cast<uint64_t>(tableIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1;
- if (UNLIKELY(lastWrittenIndex >= table->length()))
+ forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
+ uint64_t lastWrittenIndex = static_cast<uint64_t>(elementIndex) + static_cast<uint64_t>(element.functionIndices.size()) - 1;
+ if (UNLIKELY(lastWrittenIndex >= m_instance->table(tableIndex)->length()))
exception = JSValue(throwException(exec, scope, createJSWebAssemblyLinkError(exec, vm, "Element is trying to set an out of bounds table index"_s)));
});
@@ -552,7 +545,7 @@
return exception.value();
JSGlobalObject* globalObject = m_instance->globalObject(vm);
- forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex) {
+ forEachElement([&] (const Wasm::Element& element, uint32_t tableIndex, uint32_t elementIndex) {
for (uint32_t i = 0; i < element.functionIndices.size(); ++i) {
// FIXME: This essentially means we're exporting an import.
// We need a story here. We need to create a WebAssemblyFunction
@@ -568,14 +561,14 @@
// Because a WebAssemblyWrapperFunction can never wrap another WebAssemblyWrapperFunction,
// the only type this could be is WebAssemblyFunction.
RELEASE_ASSERT(wasmFunction);
- table->set(tableIndex, wasmFunction);
- ++tableIndex;
+ m_instance->table(tableIndex)->set(elementIndex, wasmFunction);
+ ++elementIndex;
continue;
}
- table->set(tableIndex,
+ m_instance->table(tableIndex)->set(elementIndex,
WebAssemblyWrapperFunction::create(vm, globalObject, globalObject->webAssemblyWrapperFunctionStructure(), functionImport, functionIndex, m_instance.get(), signatureIndex));
- ++tableIndex;
+ ++elementIndex;
continue;
}
@@ -589,8 +582,8 @@
WebAssemblyFunction* function = WebAssemblyFunction::create(
vm, globalObject, globalObject->webAssemblyFunctionStructure(), signature.argumentCount(), String(), m_instance.get(), embedderEntrypointCallee, entrypointLoadLocation, signatureIndex);
- table->set(tableIndex, function);
- ++tableIndex;
+ m_instance->table(tableIndex)->set(elementIndex, function);
+ ++elementIndex;
}
});
Modified: trunk/Source/_javascript_Core/wasm/wasm.json (246570 => 246571)
--- trunk/Source/_javascript_Core/wasm/wasm.json 2019-06-18 21:50:20 UTC (rev 246570)
+++ trunk/Source/_javascript_Core/wasm/wasm.json 2019-06-18 22:01:02 UTC (rev 246571)
@@ -67,10 +67,10 @@
"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" },
+ "table.get": { "category": "special", "value": 37, "return": ["anyref"], "parameter": ["i32"], "immediate": [{"name": "table_index", "type": "varuint32"}], "description": "get a table value" },
+ "table.set": { "category": "special", "value": 38, "return": [], "parameter": ["i32", "anyref"], "immediate": [{"name": "table_index", "type": "varuint32"}], "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" },
+ "call_indirect": { "category": "call", "value": 17, "return": ["call"], "parameter": ["call"], "immediate": [{"name": "type_index", "type": "varuint32"}, {"name": "table_index","type": "varuint32"}],"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" },
"i32.load8_u": { "category": "memory", "value": 45, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" },
"i32.load16_s": { "category": "memory", "value": 46, "return": ["i32"], "parameter": ["addr"], "immediate": [{"name": "flags", "type": "varuint32"}, {"name": "offset", "type": "varuint32"}], "description": "load from memory" },