Diff
Modified: trunk/JSTests/ChangeLog (209770 => 209771)
--- trunk/JSTests/ChangeLog 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/ChangeLog 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1,3 +1,49 @@
+2016-12-13 Saam Barati <[email protected]>
+
+ WebAssembly: implement the table section and table import
+ https://bugs.webkit.org/show_bug.cgi?id=165716
+
+ Reviewed by Keith Miller.
+
+ * wasm/Builder.js:
+ (const._importMemoryContinuation):
+ (const._importTableContinuation):
+ (export.default.Builder.prototype._registerSectionBuilders.switch.case.string_appeared_here.this.section):
+ (const._importMemoryContinuation.section): Deleted.
+ (const): Deleted.
+ (const._importMemoryContinuation.assert): Deleted.
+ * wasm/Builder_WebAssemblyBinary.js:
+ (const.putResizableLimits):
+ (const.putTable):
+ (const.emitters.Import):
+ (const.emitters.Table):
+ * wasm/function-tests/call-indirect-params.js:
+ * wasm/function-tests/call-indirect.js:
+ * wasm/function-tests/table-basic-2.js: Added.
+ (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+ (func):
+ * wasm/function-tests/table-basic.js: Added.
+ (import.Builder.from.string_appeared_here.import.as.assert.from.string_appeared_here.makeInstance):
+ * wasm/js-api/call-indirect-results.js:
+ (const.wasmModuleWhichImportJS): Deleted.
+ (MonomorphicImport): Deleted.
+ * wasm/js-api/call-indirect.js:
+ (const.wasmModuleWhichImportJS):
+ (const.makeTable):
+ (Polyphic2Import):
+ (VirtualImport):
+ (MonomorphicImport): Deleted.
+ * wasm/js-api/table.js: Added.
+ (assertBadBinary):
+ (assert.truthy):
+ (assertBadTable):
+ (assertBadTableImport):
+ (assertBadBinary.assertBadTableInstance):
+ (assertBadTableInstance):
+ (new.WebAssembly.Table):
+ * wasm/js-api/test_basic_api.js:
+ (const.c.in.constructorProperties.switch):
+
2016-12-13 Commit Queue <[email protected]>
Unreviewed, rolling out r209725.
Modified: trunk/JSTests/wasm/Builder.js (209770 => 209771)
--- trunk/JSTests/wasm/Builder.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/Builder.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -103,14 +103,23 @@
};
const _importMemoryContinuation = (builder, section, nextBuilder) => {
- return (module, field, memoryDescription) => {
- assert.isString(module, `Import function module should be a string, got "${module}"`);
- assert.isString(field, `Import function field should be a string, got "${field}"`);
- section.data.push({module, field, kind: "Memory", memoryDescription});
+ return (module, field, {initial, maximum}) => {
+ assert.isString(module, `Import Memory module should be a string, got "${module}"`);
+ assert.isString(field, `Import Memory field should be a string, got "${field}"`);
+ section.data.push({module, field, kind: "Memory", memoryDescription: {initial, maximum}});
return nextBuilder;
};
};
+const _importTableContinuation = (builder, section, nextBuilder) => {
+ return (module, field, {initial, maximum, element}) => {
+ assert.isString(module, `Import Table module should be a string, got "${module}"`);
+ assert.isString(field, `Import Table field should be a string, got "${field}"`);
+ section.data.push({module, field, kind: "Table", tableDescription: {initial, maximum, element}});
+ return nextBuilder;
+ };
+};
+
const _exportFunctionContinuation = (builder, section, nextBuilder) => {
return (field, index, type) => {
assert.isString(field, `Export function field should be a string, got "${field}"`);
@@ -299,12 +308,31 @@
if (typeof(signature) === "undefined")
signature = { params: [] };
- assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
- const [params, ret] = _normalizeFunctionSignature(signature.params, signature.ret);
- signature = { params: params, ret: ret };
+
+ let type;
+ let params;
+ if (typeof signature === "object") {
+ assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
+ let ret;
+ ([params, ret] = _normalizeFunctionSignature(signature.params, signature.ret));
+ signature = {params, ret};
+ type = _maybeRegisterType(builder, signature);
+ } else {
+ assert.truthy(typeof signature === "number");
+ const typeSection = builder._getSection("Type");
+ assert.truthy(!!typeSection);
+ // FIXME: we should allow indices that exceed this to be able to
+ // test JSCs validator is correct. https://bugs.webkit.org/show_bug.cgi?id=165786
+ assert.truthy(signature < typeSection.data.length);
+ type = signature;
+ signature = typeSection.data[signature];
+ assert.hasObjectProperty(signature, "params", `Expect function signature to be an object with a "params" field, got "${signature}"`);
+ params = signature.params;
+ }
+
const func = {
name: functionName,
- type: _maybeRegisterType(builder, signature),
+ type,
signature: signature,
locals: params.concat(locals), // Parameters are the first locals.
parameterCount: params.length,
@@ -379,11 +407,11 @@
const s = this._addSection(section);
const importBuilder = {
End: () => this,
- Table: () => { throw new Error(`Unimplemented: import table`); },
Global: () => { throw new Error(`Unimplemented: import global`); },
};
importBuilder.Function = _importFunctionContinuation(this, s, importBuilder);
importBuilder.Memory = _importMemoryContinuation(this, s, importBuilder);
+ importBuilder.Table = _importTableContinuation(this, s, importBuilder);
return importBuilder;
};
break;
@@ -400,8 +428,17 @@
break;
case "Table":
- // FIXME Implement table https://bugs.webkit.org/show_bug.cgi?id=164135
- this[section] = () => { throw new Error(`Unimplemented: section type "${section}"`); };
+ this[section] = function() {
+ const s = this._addSection(section);
+ const exportBuilder = {
+ End: () => this,
+ Table: ({initial, maximum, element}) => {
+ s.data.push({tableDescription: {initial, maximum, element}});
+ return exportBuilder;
+ }
+ };
+ return exportBuilder;
+ };
break;
case "Memory":
Modified: trunk/JSTests/wasm/Builder_WebAssemblyBinary.js (209770 => 209771)
--- trunk/JSTests/wasm/Builder_WebAssemblyBinary.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/Builder_WebAssemblyBinary.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -29,6 +29,28 @@
const put = (bin, type, value) => bin[type](value);
+const putResizableLimits = (bin, initial, maximum) => {
+ assert.truthy(typeof initial === "number", "We expect 'initial' to be an integer");
+ let hasMaximum = 0;
+ if (typeof maximum === "number") {
+ hasMaximum = 1;
+ } else {
+ assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be an integer if it's defined");
+ }
+
+ put(bin, "varuint1", hasMaximum);
+ put(bin, "varuint32", initial);
+ if (hasMaximum)
+ put(bin, "varuint32", maximum);
+};
+
+const putTable = (bin, {initial, maximum, element}) => {
+ assert.truthy(WASM.isValidType(element), "We expect 'element' to be a valid type. It was: " + element);
+ put(bin, "varint7", WASM.typeValue[element]);
+
+ putResizableLimits(bin, initial, maximum);
+};
+
const emitters = {
Type: (section, bin) => {
put(bin, "varuint32", section.data.length);
@@ -57,23 +79,13 @@
put(bin, "varuint32", entry.type);
break;
}
- case "Table": throw new Error(`Not yet implemented`);
+ case "Table": {
+ putTable(bin, entry.tableDescription);
+ break;
+ }
case "Memory": {
let {initial, maximum} = entry.memoryDescription;
- assert.truthy(typeof initial === "number", "We expect 'initial' to be a number");
- initial |= 0;
- let hasMaximum = 0;
- if (typeof maximum === "number") {
- maximum |= 0;
- hasMaximum = 1;
- } else {
- assert.truthy(typeof maximum === "undefined", "We expect 'maximum' to be a number if it's defined");
- }
-
- put(bin, "varuint1", hasMaximum);
- put(bin, "varuint32", initial);
- if (hasMaximum)
- put(bin, "varuint32", maximum);
+ putResizableLimits(bin, initial, maximum);
break;
};
case "Global": throw new Error(`Not yet implemented`);
@@ -87,7 +99,12 @@
put(bin, "varuint32", signature);
},
- Table: (section, bin) => { throw new Error(`Not yet implemented`); },
+ Table: (section, bin) => {
+ put(bin, "varuint32", section.data.length);
+ for (const {tableDescription} of section.data) {
+ putTable(bin, tableDescription);
+ }
+ },
Memory: (section, bin) => {
// Flags, currently can only be [0,1]
Modified: trunk/JSTests/wasm/function-tests/call-indirect-params.js (209770 => 209771)
--- trunk/JSTests/wasm/function-tests/call-indirect-params.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/function-tests/call-indirect-params.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1,28 +0,0 @@
-import Builder from '../Builder.js'
-
-const b = new Builder();
-b.Type().End()
- .Function().End()
- .Code()
-
- .Function({ params: ["i32"], ret: "i32" })
- .I32Const(1)
- .End()
-
- .Function({ params: ["i32"], ret: "i32" })
- .GetLocal(0)
- .End()
-
- .Function({ params: ["i32", "i32"], ret: "i32" })
- .GetLocal(1)
- .GetLocal(0)
- .CallIndirect(0, 0)
- .End()
-
-
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 3, [], [],
- [[{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }, { type: "i32", value: 4 }]],
- [{ type: "i32", value: 4 }, [{ type: "i32", value: 1 }, { type: "i32", value: 4 }]],
- ]);
Modified: trunk/JSTests/wasm/function-tests/call-indirect.js (209770 => 209771)
--- trunk/JSTests/wasm/function-tests/call-indirect.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/function-tests/call-indirect.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1,27 +0,0 @@
-import Builder from '../Builder.js'
-
-const b = new Builder();
-b.Type().End()
- .Function().End()
- .Code()
-
- .Function({ params: [], ret: "i32" })
- .I32Const(1)
- .End()
-
- .Function({ params: [], ret: "i32" })
- .I32Const(2)
- .End()
-
- .Function({ params: ["i32"], ret: "i32" })
- .GetLocal(0)
- .CallIndirect(0, 0)
- .End()
-
-
-const bin = b.WebAssembly()
-bin.trim();
-testWasmModuleFunctions(bin.get(), 3, [], [],
- [[{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
- [{ type: "i32", value: 1 }, [{ type: "i32", value: 0 }]],
- ]);
Added: trunk/JSTests/wasm/function-tests/table-basic-2.js (0 => 209771)
--- trunk/JSTests/wasm/function-tests/table-basic-2.js (rev 0)
+++ trunk/JSTests/wasm/function-tests/table-basic-2.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -0,0 +1,57 @@
+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+function makeInstance(func) {
+ const builder = new Builder()
+ .Type()
+ .Func(["i32", "i32"], "i32")
+ .Func(["i32"], "i32")
+ .End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .Function("imp", "func", { params: ["i32"], ret: "i32" })
+ .End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .Function("bar")
+ .End()
+ .Code()
+ .Function("foo", 0 /*['i32', 'i32'] => 'i32'*/)
+ .GetLocal(1) // parameter to call
+ .GetLocal(0) // call index
+ .CallIndirect(1, 0) // calling function of type ['i32'] => 'i32'
+ .Return()
+ .End()
+ .Function("bar", 1 /*['i32'] => 'i32'*/)
+ .GetLocal(0)
+ .Call(0)
+ .Return()
+ .End()
+ .End();
+
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const table = new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ return {instance: new WebAssembly.Instance(module, {imp: {table, func}}), table};
+}
+
+{
+ let i;
+ function func(x) {
+ if (x !== i)
+ throw new Error("Bad argument");
+ return x + 44;
+ }
+ const {instance, table} = makeInstance(func);
+ const exports = instance.exports;
+ const foo = exports.foo;
+ table.set(0, exports.bar);
+ assert.eq(table.get(0), exports.bar);
+
+ for (i = 0; i < 10000; i++) {
+ if (foo(0, i) !== i + 44)
+ throw new Error("Bad call indirect");
+ }
+}
Added: trunk/JSTests/wasm/function-tests/table-basic.js (0 => 209771)
--- trunk/JSTests/wasm/function-tests/table-basic.js (rev 0)
+++ trunk/JSTests/wasm/function-tests/table-basic.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -0,0 +1,67 @@
+import Builder from '../Builder.js'
+import * as assert from '../assert.js'
+
+function makeInstance() {
+ const builder = new Builder()
+ .Type()
+ .Func(["i32", "i32"], "i32")
+ .Func(["i32"], "i32")
+ .End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .Function("bar")
+ .End()
+ .Code()
+ .Function("foo", 0 /*['i32', 'i32'] => 'i32'*/)
+ .GetLocal(1) // parameter to call
+ .GetLocal(0) // call index
+ .CallIndirect(1, 0) // calling function of type ['i32'] => 'i32'
+ .Return()
+ .End()
+ .Function("bar", 1 /*['i32'] => 'i32'*/)
+ .GetLocal(0)
+ .I32Const(42)
+ .I32Add()
+ .Return()
+ .End()
+ .End();
+
+
+ const bin = builder.WebAssembly().get();
+ const module = new WebAssembly.Module(bin);
+ const table = new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ return {instance: new WebAssembly.Instance(module, {imp: {table}}), table};
+}
+
+{
+ const {instance, table} = makeInstance();
+ const exports = instance.exports;
+ const foo = exports.foo;
+ table.set(0, exports.bar);
+ assert.eq(table.get(0), exports.bar);
+
+ for (let i = 0; i < 1000; i++) {
+ if (foo(0, i) !== i + 42)
+ throw new Error("Bad call indirect");
+ }
+}
+
+// FIXME: make this work cross module. The reason it doesn't
+// now is that we don't unique Signature*.
+// https://bugs.webkit.org/show_bug.cgi?id=165511
+/*
+{
+ const {instance, table} = makeInstance();
+ const foo = instance.exports.foo;
+ //table.set(0, makeInstance().instance.exports.bar); // Cross instance function.
+
+ for (let i = 0; i < 1000; i++) {
+ if (foo(0, i) !== i + 42)
+ throw new Error("Bad call indirect");
+ }
+}
+*/
Modified: trunk/JSTests/wasm/js-api/call-indirect-results.js (209770 => 209771)
--- trunk/JSTests/wasm/js-api/call-indirect-results.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/call-indirect-results.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1,41 +0,0 @@
-import * as assert from '../assert.js';
-import Builder from '../Builder.js';
-
-const wasmModuleWhichImportJS = () => {
- const builder = (new Builder())
- .Type().End()
- .Import()
- .Function("imp", "func", { params: ["i32"], ret: "i32" })
- .End()
- .Function().End()
- .Export()
- .Function("changeCounter")
- .End()
- .Code()
- .Function("changeCounter", { params: ["i32", "i32"], ret: "i32" })
- .I32Const(42)
- .GetLocal(0)
- .I32Add()
- .GetLocal(1)
- .CallIndirect(0, 0) // Calls func(param[0] + 42).
- .I32Const(0)
- .CallIndirect(0, 0) // Calls func(param[0] + 42).
- .End()
- .End();
- const bin = builder.WebAssembly().get();
- const module = new WebAssembly.Module(bin);
- return module;
-};
-
-
-(function MonomorphicImport() {
- let counter = 0;
- const counterSetter = v => counter = v;
- const module = wasmModuleWhichImportJS();
- const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter } });
- 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.
- instance.exports.changeCounter(i, 0);
- assert.eq(counter, i + 42);
- }
-})();
Modified: trunk/JSTests/wasm/js-api/call-indirect.js (209770 => 209771)
--- trunk/JSTests/wasm/js-api/call-indirect.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/call-indirect.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -6,10 +6,12 @@
.Type().End()
.Import()
.Function("imp", "func", { params: ["i32"] })
+ .Table("imp", "table", { initial: 1, maximum: 1, element: "anyfunc"})
.End()
.Function().End()
.Export()
.Function("changeCounter")
+ .Function("callFunc")
.End()
.Code()
.Function("changeCounter", { params: ["i32", "i32"] })
@@ -17,8 +19,12 @@
.GetLocal(0)
.I32Add()
.GetLocal(1)
- .CallIndirect(0, 0) // Calls func(param[0] + 42).
+ .CallIndirect(0, 0) // 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);
@@ -25,12 +31,17 @@
return module;
};
+const makeTable = () => {
+ return new WebAssembly.Table({initial: 1, maximum: 1, element: "anyfunc"});
+};
(function MonomorphicImport() {
let counter = 0;
const counterSetter = v => counter = v;
+ const table = makeTable();
const module = wasmModuleWhichImportJS();
- const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter } });
+ const instance = new WebAssembly.Instance(module, { imp: { func: counterSetter, table} });
+ 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.
instance.exports.changeCounter(i, 0);
@@ -44,8 +55,14 @@
const counterASetter = v => counterA = v;
const counterBSetter = v => counterB = { valueB: v };
const module = wasmModuleWhichImportJS();
- const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter } });
- const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter } });
+
+ const tableA = makeTable();
+ const instanceA = new WebAssembly.Instance(module, { imp: { func: counterASetter, table: tableA} });
+ tableA.set(0, instanceA.exports.callFunc);
+
+ const tableB = makeTable();
+ const instanceB = new WebAssembly.Instance(module, { imp: { func: counterBSetter, table: tableB} });
+ tableB.set(0, instanceB.exports.callFunc);
for (let i = 0; i < 2048; ++i) {
instanceA.exports.changeCounter(i, 0);
assert.isA(counterA, "number");
@@ -57,8 +74,6 @@
})();
(function VirtualImport() {
- const num = 10; // It's definitely going virtual at 10!
- let counters = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const counterSetters = [
v => counters[0] = v,
v => counters[1] = v + 1,
@@ -71,12 +86,16 @@
v => counters[8] = v + 8,
v => counters[9] = v + 9,
];
+ const num = counterSetters.length;
+ let counters = counterSetters.map(() => 0);
assert.eq(counters.length, num);
- assert.eq(counterSetters.length, num);
const module = wasmModuleWhichImportJS();
let instances = [];
- for (let i = 0; i < num; ++i)
- instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i] } });
+ for (let i = 0; i < num; ++i) {
+ let table = makeTable();
+ instances[i] = new WebAssembly.Instance(module, { imp: { func: counterSetters[i], table} });
+ table.set(0, instances[i].exports.callFunc);
+ }
for (let i = 0; i < 2048; ++i) {
for (let j = 0; j < num; ++j) {
instances[j].exports.changeCounter(i, 0);
Added: trunk/JSTests/wasm/js-api/table.js (0 => 209771)
--- trunk/JSTests/wasm/js-api/table.js (rev 0)
+++ trunk/JSTests/wasm/js-api/table.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -0,0 +1,230 @@
+import Builder from '../Builder.js';
+import * as assert from '../assert.js';
+
+const badTableString = "couldn't parse section Table";
+const badImportString = "couldn't parse section Import";
+function assertBadBinary(builder, str) {
+ const bin = builder.WebAssembly().get();
+ let threw = false;
+ try {
+ new WebAssembly.Module(bin);
+ } catch(e) {
+ threw = true;
+ assert.truthy(e.toString().indexOf(str) !== -1);
+ assert.truthy(e instanceof WebAssembly.CompileError);
+ }
+ assert.truthy(threw);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .Table({initial: 20, maximum: 30, element: "anyfunc"})
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Export()
+ .Function("foo")
+ .End()
+ .Code()
+ .Function("foo", {params: ["i32"]})
+ .GetLocal(0)
+ .CallIndirect(0, 0)
+ .End()
+ .End();
+ assertBadBinary(builder, "call_indirect is only valid when a table is defined or imported");
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table({initial:20, element:"anyfunc"})
+ .End()
+ .Export()
+ .Function("foo")
+ .End()
+ .Code()
+ .Function("foo", {params: ["i32"]})
+ .GetLocal(0)
+ .CallIndirect(0, 1)
+ .End()
+ .End();
+ assertBadBinary(builder, "call_indirect 'reserved' varuint1 must be 0x0");
+}
+
+function assertBadTable(tableDescription) {
+ const builder = new Builder()
+ .Type().End()
+ .Function().End()
+ .Table()
+ .Table(tableDescription)
+ .End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badTableString);
+}
+
+function assertBadTableImport(tableDescription) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", tableDescription)
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badImportString);
+}
+
+{
+ let badDescriptions = [
+ {initial: 10, element: "i32"},
+ {initial: 10, element: "f32"},
+ {initial: 10, element: "f64"},
+ {initial: 10, element: "i64"},
+ {initial: 10, maximum: 20, element: "i32"},
+ {initial: 10, maximum: 20, element: "f32"},
+ {initial: 10, maximum: 20, element: "f64"},
+ {initial: 10, maximum: 20, element: "i64"},
+
+ {initial: 10, maximum: 9, element: "anyfunc"},
+ {initial: 1, maximum: 0, element: "anyfunc"},
+ {initial: 2**32 - 1, maximum: 2**32 - 2, element: "anyfunc"},
+ {initial: 2**31, element: "anyfunc"},
+ ];
+
+ for (const d of badDescriptions) {
+ assertBadTable(d);
+ assertBadTableImport(d);
+ }
+}
+
+{
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .Table("imp", "table", {initial: 20, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ assertBadBinary(builder, badImportString);
+}
+
+
+{
+ function assertBadTableInstance(tableDescription, table, message) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", tableDescription)
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+
+ let threw = false;
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ try {
+ new WebAssembly.Instance(module, {imp: {table}});
+ } catch (e) {
+ assert.eq(e.toString(), message);
+ threw = true;
+ }
+ assert.truthy(threw);
+ }
+
+ const badTables = [
+ [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, element: "anyfunc"}), "TypeError: Table import does not have a 'maximum' but the module requires that it does"],
+ [{initial: 100, maximum:100, element:"anyfunc"}, new WebAssembly.Table({initial:100, maximum:101, element: "anyfunc"}), "TypeError: Imported Table's 'maximum' is larger than the module's expected 'maximum'"],
+ [{initial: 100, element:"anyfunc"}, new WebAssembly.Table({initial:10, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
+ [{initial: 10, element:"anyfunc"}, new WebAssembly.Table({initial:9, element: "anyfunc"}), "TypeError: Table import provided an 'initial' that is too small"],
+ ];
+ for (const [d, t, m] of badTables) {
+ assertBadTableInstance(d, t, m);
+ }
+}
+
+{
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20, maximum: 30});
+ table.grow(30);
+ assert.throws(() => table.grow(31), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ assert.throws(() => table.grow(29), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.grow({valueOf() { return 19; }}), TypeError, "WebAssembly.Table.prototype.grow could not grow the table");
+ let called = false;
+ table.grow({valueOf() { called = true; return 21; }});
+ assert.truthy(called);
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.get(20), RangeError, "WebAssembly.Table.prototype.get expects an integer less than the size of the table");
+ for (let i = 0; i < 20; i++)
+ assert.eq(table.get(i), null);
+ }
+
+ {
+ const table = new WebAssembly.Table({element: "anyfunc", initial: 20});
+ assert.throws(() => table.set(20, null), RangeError, "WebAssembly.Table.prototype.set expects an integer less than the size of the table");
+ for (let i = 0; i < 20; i++)
+ table.set(i, null);
+ }
+
+ {
+ // This should not throw
+ new WebAssembly.Table({initial: 2**20, maximum: 2**32 - 1, element: "anyfunc"});
+ }
+}
+
+{
+
+ function assertBadTable(table) {
+ const builder = new Builder()
+ .Type().End()
+ .Import()
+ .Table("imp", "table", {initial: 25, element: "anyfunc"})
+ .End()
+ .Function().End()
+ .Code()
+ .End();
+ const module = new WebAssembly.Module(builder.WebAssembly().get());
+ assert.throws(() => new WebAssembly.Instance(module, {imp: {table}}), TypeError, "Table import is not an instance of WebAssembly.Table");
+ }
+ assertBadTable(25);
+ assertBadTable(new Object);
+ assertBadTable([]);
+ assertBadTable(new WebAssembly.Memory({initial:1}));
+}
Modified: trunk/JSTests/wasm/js-api/test_basic_api.js (209770 => 209771)
--- trunk/JSTests/wasm/js-api/test_basic_api.js 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/JSTests/wasm/js-api/test_basic_api.js 2016-12-13 20:32:40 UTC (rev 209771)
@@ -78,8 +78,9 @@
new WebAssembly.Memory({initial: 20});
break;
case "Table":
- // FIXME Implement and test these APIs further. For now they just throw. https://bugs.webkit.org/show_bug.cgi?id=159775
- assert.throws(() => new WebAssembly[c](), Error, `WebAssembly doesn't yet implement the ${c} constructor property`);
+ new WebAssembly.Table({initial: 20, element: "anyfunc"});
+ new WebAssembly.Table({initial: 20, maximum: 20, element: "anyfunc"});
+ new WebAssembly.Table({initial: 20, maximum: 25, element: "anyfunc"});
break;
case "CompileError":
case "RuntimeError": {
Modified: trunk/Source/_javascript_Core/ChangeLog (209770 => 209771)
--- trunk/Source/_javascript_Core/ChangeLog 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/ChangeLog 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1,3 +1,96 @@
+2016-12-13 Saam Barati <[email protected]>
+
+ WebAssembly: implement the table section and table import
+ https://bugs.webkit.org/show_bug.cgi?id=165716
+
+ Reviewed by Keith Miller.
+
+ This patch implements the Table space for wasm:
+ https://github.com/WebAssembly/design/blob/master/BinaryEncoding.md#table-section
+
+ It only implements defining and importing a table. The bulk
+ of this patch is implementing the various wasm Table prototype
+ methods and the underlying Table object:
+ https://github.com/WebAssembly/design/blob/master/JS.md#webassemblytable-constructor
+
+ This patch also fixes a bug in our implementation with call_indirect.
+ We initially implemented call_indirect as a way to call functions that
+ are imported or defined in the module. This was the wrong
+ interpretation of the spec. Instead, call_indirect can only index into
+ the table index space.
+
+ * _javascript_Core.xcodeproj/project.pbxproj:
+ * wasm/WasmB3IRGenerator.cpp:
+ (JSC::Wasm::B3IRGenerator::B3IRGenerator):
+ (JSC::Wasm::B3IRGenerator::addCallIndirect):
+ (JSC::Wasm::parseAndCompile):
+ * wasm/WasmFormat.h:
+ (JSC::Wasm::TableInformation::TableInformation):
+ (JSC::Wasm::TableInformation::operator bool):
+ (JSC::Wasm::TableInformation::isImport):
+ (JSC::Wasm::TableInformation::initial):
+ (JSC::Wasm::TableInformation::maximum):
+ (JSC::Wasm::CallableFunction::CallableFunction):
+ * wasm/WasmFunctionParser.h:
+ (JSC::Wasm::FunctionParser<Context>::parseExpression):
+ * wasm/WasmModuleParser.cpp:
+ (JSC::Wasm::ModuleParser::parseImport):
+ (JSC::Wasm::ModuleParser::parseResizableLimits):
+ (JSC::Wasm::ModuleParser::parseTableHelper):
+ (JSC::Wasm::ModuleParser::parseTable):
+ (JSC::Wasm::ModuleParser::parseMemoryHelper):
+ (JSC::Wasm::ModuleParser::parseExport):
+ * wasm/WasmModuleParser.h:
+ * wasm/js/JSWebAssemblyHelpers.h: Added.
+ (JSC::toNonWrappingUint32):
+ * wasm/js/JSWebAssemblyInstance.cpp:
+ (JSC::JSWebAssemblyInstance::visitChildren):
+ * wasm/js/JSWebAssemblyInstance.h:
+ (JSC::JSWebAssemblyInstance::table):
+ (JSC::JSWebAssemblyInstance::setTable):
+ (JSC::JSWebAssemblyInstance::offsetOfTable):
+ * wasm/js/JSWebAssemblyTable.cpp:
+ (JSC::JSWebAssemblyTable::create):
+ (JSC::JSWebAssemblyTable::JSWebAssemblyTable):
+ (JSC::JSWebAssemblyTable::visitChildren):
+ (JSC::JSWebAssemblyTable::grow):
+ (JSC::JSWebAssemblyTable::clearFunction):
+ (JSC::JSWebAssemblyTable::setFunction):
+ * wasm/js/JSWebAssemblyTable.h:
+ (JSC::JSWebAssemblyTable::maximum):
+ (JSC::JSWebAssemblyTable::size):
+ (JSC::JSWebAssemblyTable::getFunction):
+ (JSC::JSWebAssemblyTable::offsetOfSize):
+ (JSC::JSWebAssemblyTable::offsetOfFunctions):
+ (JSC::JSWebAssemblyTable::isValidSize):
+ * wasm/js/WebAssemblyFunction.cpp:
+ (JSC::WebAssemblyFunction::call):
+ (JSC::WebAssemblyFunction::create):
+ (JSC::WebAssemblyFunction::visitChildren):
+ (JSC::WebAssemblyFunction::finishCreation):
+ * wasm/js/WebAssemblyFunction.h:
+ (JSC::WebAssemblyFunction::signature):
+ (JSC::WebAssemblyFunction::wasmEntrypoint):
+ (JSC::WebAssemblyFunction::webAssemblyCallee): Deleted.
+ * wasm/js/WebAssemblyInstanceConstructor.cpp:
+ (JSC::constructJSWebAssemblyInstance):
+ * wasm/js/WebAssemblyMemoryConstructor.cpp:
+ (JSC::constructJSWebAssemblyMemory):
+ * wasm/js/WebAssemblyModuleRecord.cpp:
+ (JSC::WebAssemblyModuleRecord::finishCreation):
+ (JSC::WebAssemblyModuleRecord::link):
+ * wasm/js/WebAssemblyTableConstructor.cpp:
+ (JSC::constructJSWebAssemblyTable):
+ * wasm/js/WebAssemblyTablePrototype.cpp:
+ (JSC::getTable):
+ (JSC::webAssemblyTableProtoFuncLength):
+ (JSC::webAssemblyTableProtoFuncGrow):
+ (JSC::webAssemblyTableProtoFuncGet):
+ (JSC::webAssemblyTableProtoFuncSet):
+ (JSC::WebAssemblyTablePrototype::create):
+ (JSC::WebAssemblyTablePrototype::finishCreation):
+ * wasm/js/WebAssemblyTablePrototype.h:
+
2016-12-13 Filip Pizlo <[email protected]>
Add null checks to opaque root APIs.
Modified: trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj (209770 => 209771)
--- trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/_javascript_Core.xcodeproj/project.pbxproj 2016-12-13 20:32:40 UTC (rev 209771)
@@ -1413,6 +1413,7 @@
795B19971D78BE3500262FA0 /* MapBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 795B19951D78BE3500262FA0 /* MapBase.cpp */; };
795B19981D78BE3500262FA0 /* MapBase.h in Headers */ = {isa = PBXBuildFile; fileRef = 795B19961D78BE3500262FA0 /* MapBase.h */; settings = {ATTRIBUTES = (Private, ); }; };
7964656A1B952FF0003059EE /* GetPutInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 796465681B952FF0003059EE /* GetPutInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
+ 796FB43A1DFF8C3F0039C95D /* JSWebAssemblyHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; };
797E07A91B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */; };
797E07AA1B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = 797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */; settings = {ATTRIBUTES = (Private, ); }; };
798937781DCAB57300F8D4FB /* JSFixedArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 798937761DCAB57300F8D4FB /* JSFixedArray.cpp */; };
@@ -3842,6 +3843,7 @@
795B19951D78BE3500262FA0 /* MapBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MapBase.cpp; sourceTree = "<group>"; };
795B19961D78BE3500262FA0 /* MapBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MapBase.h; sourceTree = "<group>"; };
796465681B952FF0003059EE /* GetPutInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GetPutInfo.h; sourceTree = "<group>"; };
+ 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSWebAssemblyHelpers.h; path = js/JSWebAssemblyHelpers.h; sourceTree = "<group>"; };
797E07A71B8FCFB9008400BA /* JSGlobalLexicalEnvironment.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSGlobalLexicalEnvironment.cpp; sourceTree = "<group>"; };
797E07A81B8FCFB9008400BA /* JSGlobalLexicalEnvironment.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalLexicalEnvironment.h; sourceTree = "<group>"; };
798937761DCAB57300F8D4FB /* JSFixedArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSFixedArray.cpp; sourceTree = "<group>"; };
@@ -7586,6 +7588,7 @@
79E423E11DEE65320078D355 /* JSWebAssemblyCallee.h */,
AD2FCBA61DB58DA400B3E736 /* JSWebAssemblyCompileError.cpp */,
AD2FCBA71DB58DA400B3E736 /* JSWebAssemblyCompileError.h */,
+ 796FB4391DFF8C3F0039C95D /* JSWebAssemblyHelpers.h */,
AD2FCBA81DB58DA400B3E736 /* JSWebAssemblyInstance.cpp */,
AD2FCBA91DB58DA400B3E736 /* JSWebAssemblyInstance.h */,
AD2FCBAA1DB58DA400B3E736 /* JSWebAssemblyMemory.cpp */,
@@ -8695,6 +8698,7 @@
43422A671C16267800E2EB98 /* B3ReduceDoubleToFloat.h in Headers */,
0F070A4B1D543A98006E7232 /* LargeAllocation.h in Headers */,
86D3B2C610156BDE002865E7 /* MacroAssemblerARM.h in Headers */,
+ 796FB43A1DFF8C3F0039C95D /* JSWebAssemblyHelpers.h in Headers */,
A1A009C01831A22D00CF8711 /* MacroAssemblerARM64.h in Headers */,
86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */,
863B23E00FC6118900703AA4 /* MacroAssemblerCodeRef.h in Headers */,
Modified: trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/WasmB3IRGenerator.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -137,7 +137,7 @@
static constexpr ExpressionType emptyExpression = nullptr;
- B3IRGenerator(const MemoryInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
+ B3IRGenerator(VM&, const MemoryInformation&, Procedure&, WasmInternalFunction*, Vector<UnlinkedWasmToWasmCall>&, const ImmutableFunctionIndexSpace&);
bool WARN_UNUSED_RETURN addArguments(const Vector<Type>&);
bool WARN_UNUSED_RETURN addLocal(Type, uint32_t);
@@ -188,6 +188,7 @@
void unifyValuesWithBlock(const ExpressionList& resultStack, ResultList& stack);
Value* zeroForType(Type);
+ VM& m_vm;
const ImmutableFunctionIndexSpace& m_functionIndexSpace;
Procedure& m_proc;
BasicBlock* m_currentBlock;
@@ -199,8 +200,9 @@
Value* m_functionIndexSpaceValue;
};
-B3IRGenerator::B3IRGenerator(const MemoryInformation& memory, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
- : m_functionIndexSpace(functionIndexSpace)
+B3IRGenerator::B3IRGenerator(VM& vm, const MemoryInformation& memory, Procedure& procedure, WasmInternalFunction* compilation, Vector<UnlinkedWasmToWasmCall>& unlinkedWasmToWasmCalls, const ImmutableFunctionIndexSpace& functionIndexSpace)
+ : m_vm(vm)
+ , m_functionIndexSpace(functionIndexSpace)
, m_proc(procedure)
, m_unlinkedWasmToWasmCalls(unlinkedWasmToWasmCalls)
{
@@ -669,12 +671,23 @@
ExpressionType calleeIndex = args.takeLast();
ASSERT(signature->arguments.size() == args.size());
+ ExpressionType callableFunctionBuffer;
+ ExpressionType callableFunctionBufferSize;
+ {
+ ExpressionType topInstance = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), &m_vm.topJSWebAssemblyInstance));
+ ExpressionType table = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ topInstance, JSWebAssemblyInstance::offsetOfTable());
+ callableFunctionBuffer = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(),
+ table, JSWebAssemblyTable::offsetOfFunctions());
+ callableFunctionBufferSize = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, Int32, Origin(),
+ table, JSWebAssemblyTable::offsetOfSize());
+ }
+
// Check the index we are looking for is valid.
{
- ExpressionType maxValidIndex = m_currentBlock->appendIntConstant(m_proc, Origin(), Int32, m_functionIndexSpace.size);
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
- m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(), m_zeroValues[linearizeType(I32)],
- m_currentBlock->appendNew<Value>(m_proc, LessThan, Origin(), calleeIndex, maxValidIndex)));
+ m_currentBlock->appendNew<Value>(m_proc, AboveEqual, Origin(), calleeIndex, callableFunctionBufferSize));
check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
jit.breakpoint();
@@ -681,15 +694,27 @@
});
}
- // Compute the offset in the function index space we are looking for.
+ // Compute the offset in the table index space we are looking for.
ExpressionType offset = m_currentBlock->appendNew<Value>(m_proc, Mul, Origin(),
m_currentBlock->appendNew<Value>(m_proc, ZExt32, Origin(), calleeIndex),
m_currentBlock->appendIntConstant(m_proc, Origin(), pointerType(), sizeof(CallableFunction)));
- ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), m_functionIndexSpaceValue, offset);
+ ExpressionType callableFunction = m_currentBlock->appendNew<Value>(m_proc, Add, Origin(), callableFunctionBuffer, offset);
+ // Check that the CallableFunction is initialized. We trap if it isn't. A null Signature* indicates it's not initialized.
+ ExpressionType calleeSignature = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signature));
+ {
+ CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
+ m_currentBlock->appendNew<Value>(m_proc, Equal, Origin(),
+ calleeSignature,
+ m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), 0)));
+
+ check->setGenerator([] (CCallHelpers& jit, const B3::StackmapGenerationParams&) {
+ jit.breakpoint();
+ });
+ }
+
// Check the signature matches the value we expect.
{
- ExpressionType calleeSignature = m_currentBlock->appendNew<MemoryValue>(m_proc, Load, pointerType(), Origin(), callableFunction, OBJECT_OFFSETOF(CallableFunction, signature));
ExpressionType expectedSignature = m_currentBlock->appendNew<ConstPtrValue>(m_proc, Origin(), signature);
CheckValue* check = m_currentBlock->appendNew<CheckValue>(m_proc, Check, Origin(),
m_currentBlock->appendNew<Value>(m_proc, NotEqual, Origin(), calleeSignature, expectedSignature));
@@ -713,6 +738,7 @@
jit.call(params[returnType == Void ? 0 : 1].gpr());
});
});
+
return true;
}
@@ -846,7 +872,7 @@
auto result = std::make_unique<WasmInternalFunction>();
Procedure procedure;
- B3IRGenerator context(info.memory, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
+ B3IRGenerator context(vm, info.memory, procedure, result.get(), unlinkedWasmToWasmCalls, functionIndexSpace);
FunctionParser<B3IRGenerator> parser(context, functionStart, functionLength, signature, functionIndexSpace, info);
if (!parser.parse())
RELEASE_ASSERT_NOT_REACHED();
Modified: trunk/Source/_javascript_Core/wasm/WasmFormat.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/WasmFormat.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/WasmFormat.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -106,7 +106,7 @@
External::Kind kind;
union {
uint32_t functionIndex;
- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
+ // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=165782
// FIXME implement Memory https://bugs.webkit.org/show_bug.cgi?id=165671
// FIXME implement Global https://bugs.webkit.org/show_bug.cgi?id=164133
};
@@ -147,11 +147,38 @@
}
};
+class TableInformation {
+public:
+ TableInformation()
+ {
+ ASSERT(!*this);
+ }
+
+ TableInformation(uint32_t initial, std::optional<uint32_t> maximum, bool isImport)
+ : m_initial(initial)
+ , m_maximum(maximum)
+ , m_isImport(isImport)
+ , m_isValid(true)
+ {
+ ASSERT(*this);
+ }
+
+ explicit operator bool() const { return m_isValid; }
+ bool isImport() const { return m_isImport; }
+ uint32_t initial() const { return m_initial; }
+ std::optional<uint32_t> maximum() const { return m_maximum; }
+
+private:
+ uint32_t m_initial;
+ std::optional<uint32_t> m_maximum;
+ bool m_isImport { false };
+ bool m_isValid { false };
+};
+
struct ModuleInformation {
Vector<Signature> signatures;
Vector<Import> imports;
Vector<Signature*> importFunctions;
- // FIXME implement import Table https://bugs.webkit.org/show_bug.cgi?id=164135
// FIXME implement import Global https://bugs.webkit.org/show_bug.cgi?id=164133
Vector<Signature*> internalFunctionSignatures;
MemoryInformation memory;
@@ -158,6 +185,7 @@
Vector<Export> exports;
std::optional<uint32_t> startFunctionIndexSpace;
Vector<Segment::Ptr> data;
+ TableInformation tableInformation;
~ModuleInformation();
};
@@ -185,13 +213,18 @@
// WebAssembly direct calls and call_indirect use indices into "function index space". This space starts with all imports, and then all internal functions.
// CallableFunction and FunctionIndexSpace are only meant as fast lookup tables for these opcodes, and do not own code.
struct CallableFunction {
- CallableFunction(Signature* signature)
+ CallableFunction() = default;
+
+ CallableFunction(Signature* signature, void* code = nullptr)
: signature(signature)
- , code(nullptr)
+ , code(code)
{
}
- Signature* signature; // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures), and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
- void* code;
+
+ // FIXME pack this inside a (uniqued) integer (for correctness the parser should unique Signatures),
+ // and then pack that integer into the code pointer. https://bugs.webkit.org/show_bug.cgi?id=165511
+ Signature* signature { nullptr };
+ void* code { nullptr };
};
typedef Vector<CallableFunction> FunctionIndexSpace;
Modified: trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/WasmFunctionParser.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -382,6 +382,8 @@
}
case OpType::CallIndirect: {
+ if (!m_info.tableInformation)
+ return setErrorMessage("call_indirect is only valid when a table is defined or imported");
uint32_t signatureIndex;
if (!parseVarUInt32(signatureIndex))
return false;
@@ -390,6 +392,9 @@
if (!parseVarUInt1(reserved))
return false;
+ if (reserved != 0)
+ return setErrorMessage("call_indirect 'reserved' varuint1 must be 0x0");
+
if (m_info.signatures.size() <= signatureIndex)
return setErrorMessage("Tried to use a signature outside the range of valid signatures");
Modified: trunk/Source/_javascript_Core/wasm/WasmModuleParser.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/WasmModuleParser.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/WasmModuleParser.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -29,6 +29,7 @@
#if ENABLE(WEBASSEMBLY)
#include "IdentifierInlines.h"
+#include "JSWebAssemblyTable.h"
#include "WasmFormat.h"
#include "WasmMemoryInformation.h"
#include "WasmOps.h"
@@ -250,7 +251,9 @@
break;
}
case External::Table: {
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
+ bool isImport = true;
+ if (!parseTableHelper(isImport))
+ return false;
break;
}
case External::Memory: {
@@ -300,45 +303,101 @@
return true;
}
-bool ModuleParser::parseTable()
+bool ModuleParser::parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum)
{
- // FIXME implement table https://bugs.webkit.org/show_bug.cgi?id=164135
- RELEASE_ASSERT_NOT_REACHED();
+ ASSERT(!maximum);
+
+ uint8_t flags;
+ if (!parseVarUInt1(flags))
+ return false;
+
+ if (!parseVarUInt32(initial))
+ return false;
+
+ if (flags) {
+ uint32_t maximumInt;
+ if (!parseVarUInt32(maximumInt))
+ return false;
+
+ if (initial > maximumInt)
+ return false;
+
+ maximum = maximumInt;
+ }
+
return true;
}
-bool ModuleParser::parseMemoryHelper(bool isImport)
+bool ModuleParser::parseTableHelper(bool isImport)
{
- // We don't allow redeclaring memory. Either via import or definition.
- if (m_module->memory)
+ // We're only allowed a total of one Table import or definition.
+ if (m_hasTable)
return false;
- uint8_t flags;
- if (!parseVarUInt1(flags))
+ m_hasTable = true;
+
+ int8_t type;
+ if (!parseInt7(type))
return false;
+ if (type != Wasm::Anyfunc)
+ return false;
uint32_t initial;
- if (!parseVarUInt32(initial))
+ std::optional<uint32_t> maximum;
+ if (!parseResizableLimits(initial, maximum))
return false;
- if (!PageCount::isValid(initial))
+ if (!JSWebAssemblyTable::isValidSize(initial))
return false;
- PageCount initialPageCount(initial);
+ ASSERT(!maximum || *maximum >= initial);
+ m_module->tableInformation = TableInformation(initial, maximum, isImport);
+
+ return true;
+}
+
+bool ModuleParser::parseTable()
+{
+ uint32_t count;
+ if (!parseVarUInt32(count))
+ return false;
+
+ // We only allow one table for now.
+ if (count != 1)
+ return false;
+
+ bool isImport = false;
+ return parseTableHelper(isImport);
+}
+
+bool ModuleParser::parseMemoryHelper(bool isImport)
+{
+ // We don't allow redeclaring memory. Either via import or definition.
+ if (m_module->memory)
+ return false;
+
+ PageCount initialPageCount;
PageCount maximumPageCount;
- if (flags) {
- uint32_t maximum;
- if (!parseVarUInt32(maximum))
+ {
+ uint32_t initial;
+ std::optional<uint32_t> maximum;
+ if (!parseResizableLimits(initial, maximum))
return false;
-
- if (!PageCount::isValid(maximum))
+ ASSERT(!maximum || *maximum >= initial);
+ if (!PageCount::isValid(initial))
return false;
- maximumPageCount = PageCount(maximum);
- if (initialPageCount > maximumPageCount)
- return false;
+ initialPageCount = PageCount(initial);
+
+ if (maximum) {
+ if (!PageCount::isValid(*maximum))
+ return false;
+ maximumPageCount = PageCount(*maximum);
+ }
}
+ ASSERT(initialPageCount);
+ ASSERT(!maximumPageCount || maximumPageCount >= initialPageCount);
Vector<unsigned> pinnedSizes = { 0 };
m_module->memory = MemoryInformation(initialPageCount, maximumPageCount, pinnedSizes, isImport);
@@ -397,7 +456,7 @@
break;
}
case External::Table: {
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
break;
}
case External::Memory: {
Modified: trunk/Source/_javascript_Core/wasm/WasmModuleParser.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/WasmModuleParser.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/WasmModuleParser.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -79,6 +79,8 @@
#undef WASM_SECTION_DECLARE_PARSER
bool WARN_UNUSED_RETURN parseMemoryHelper(bool isImport);
+ bool WARN_UNUSED_RETURN parseTableHelper(bool isImport);
+ bool WARN_UNUSED_RETURN parseResizableLimits(uint32_t& initial, std::optional<uint32_t>& maximum);
VM* m_vm;
std::unique_ptr<ModuleInformation> m_module;
@@ -85,6 +87,7 @@
FunctionIndexSpace m_functionIndexSpace;
Vector<FunctionLocationInBinary> m_functionLocationInBinary;
bool m_failed { true };
+ bool m_hasTable { false };
String m_errorMessage;
};
Added: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h (0 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h (rev 0)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyHelpers.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(WEBASSEMBLY)
+
+#include "JSCJSValue.h"
+
+namespace JSC {
+
+ALWAYS_INLINE uint32_t toNonWrappingUint32(ExecState* exec, JSValue value)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ double doubleValue = value.toInteger(exec);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (doubleValue < 0 || doubleValue > UINT_MAX) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("Expect an integer argument in the range: [0, 2^32 - 1]")));
+ return { };
+ }
+
+ return static_cast<uint32_t>(doubleValue);
+}
+
+} // namespace JSC
+
+#endif // ENABLE(WEBASSEMBLY)
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -80,6 +80,7 @@
visitor.append(&thisObject->m_module);
visitor.append(&thisObject->m_moduleNamespaceObject);
visitor.append(&thisObject->m_memory);
+ visitor.append(&thisObject->m_table);
for (unsigned i = 0; i < thisObject->m_numImportFunctions; ++i)
visitor.append(thisObject->importFunction(i));
}
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyInstance.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -30,6 +30,7 @@
#include "JSDestructibleObject.h"
#include "JSObject.h"
#include "JSWebAssemblyMemory.h"
+#include "JSWebAssemblyTable.h"
namespace JSC {
@@ -71,11 +72,16 @@
JSWebAssemblyMemory* memory() { return m_memory.get(); }
void setMemory(VM& vm, JSWebAssemblyMemory* memory) { m_memory.set(vm, this, memory); }
+ JSWebAssemblyTable* table() { return m_table.get(); }
+ void setTable(VM& vm, JSWebAssemblyTable* table) { m_table.set(vm, this, table); }
+
static size_t offsetOfImportFunction(unsigned idx)
{
return offsetOfImportFunctions() + sizeof(WriteBarrier<JSCell>) * idx;
}
+ static ptrdiff_t offsetOfTable() { return OBJECT_OFFSETOF(JSWebAssemblyInstance, m_table); }
+
protected:
JSWebAssemblyInstance(VM&, Structure*, unsigned);
void finishCreation(VM&, JSWebAssemblyModule*, JSModuleNamespaceObject*);
@@ -96,6 +102,7 @@
WriteBarrier<JSWebAssemblyModule> m_module;
WriteBarrier<JSModuleNamespaceObject> m_moduleNamespaceObject;
WriteBarrier<JSWebAssemblyMemory> m_memory;
+ WriteBarrier<JSWebAssemblyTable> m_table;
unsigned m_numImportFunctions;
};
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -29,12 +29,21 @@
#if ENABLE(WEBASSEMBLY)
#include "JSCInlines.h"
+#include "WasmFormat.h"
namespace JSC {
-JSWebAssemblyTable* JSWebAssemblyTable::create(VM& vm, Structure* structure)
+const ClassInfo JSWebAssemblyTable::s_info = { "WebAssembly.Table", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyTable) };
+
+JSWebAssemblyTable* JSWebAssemblyTable::create(ExecState* exec, VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
{
- auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure);
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ if (!isValidSize(initial)) {
+ throwException(exec, throwScope, createOutOfMemoryError(exec));
+ return nullptr;
+ }
+
+ auto* instance = new (NotNull, allocateCell<JSWebAssemblyTable>(vm.heap)) JSWebAssemblyTable(vm, structure, initial, maximum);
instance->finishCreation(vm);
return instance;
}
@@ -44,9 +53,23 @@
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
-JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure)
+JSWebAssemblyTable::JSWebAssemblyTable(VM& vm, Structure* structure, uint32_t initial, std::optional<uint32_t> maximum)
: Base(vm, structure)
{
+ m_size = initial;
+ ASSERT(isValidSize(m_size));
+ m_maximum = maximum;
+ ASSERT(!m_maximum || *m_maximum >= m_size);
+
+ // 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_functions = MallocPtr<Wasm::CallableFunction>::malloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(m_size));
+ m_jsFunctions = MallocPtr<WriteBarrier<WebAssemblyFunction>>::malloc(sizeof(WriteBarrier<WebAssemblyFunction>) * static_cast<size_t>(m_size));
+ for (uint32_t i = 0; i < m_size; ++i) {
+ new (&m_functions.get()[i]) Wasm::CallableFunction();
+ ASSERT(!m_functions.get()[i].signature); // We rely on this in compiled code.
+ new (&m_jsFunctions.get()[i]) WriteBarrier<WebAssemblyFunction>();
+ }
}
void JSWebAssemblyTable::finishCreation(VM& vm)
@@ -62,14 +85,52 @@
void JSWebAssemblyTable::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- auto* thisObject = jsCast<JSWebAssemblyTable*>(cell);
+ JSWebAssemblyTable* thisObject = jsCast<JSWebAssemblyTable*>(cell);
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
+
+ for (unsigned i = 0; i < thisObject->m_size; ++i)
+ visitor.append(&thisObject->m_jsFunctions.get()[i]);
}
-const ClassInfo JSWebAssemblyTable::s_info = { "WebAssembly.Table", &Base::s_info, 0, CREATE_METHOD_TABLE(JSWebAssemblyTable) };
+bool JSWebAssemblyTable::grow(uint32_t newSize)
+{
+ if (newSize < m_size)
+ return false;
+ if (newSize == m_size)
+ return true;
+ if (maximum() && newSize > *maximum())
+ return false;
+ if (!isValidSize(newSize))
+ return false;
+ m_functions.realloc(sizeof(Wasm::CallableFunction) * static_cast<size_t>(newSize));
+ m_jsFunctions.realloc(sizeof(WriteBarrier<WebAssemblyFunction>) * static_cast<size_t>(newSize));
+
+ for (uint32_t i = m_size; i < newSize; ++i) {
+ new (&m_functions.get()[i]) Wasm::CallableFunction();
+ new (&m_jsFunctions.get()[i]) WriteBarrier<WebAssemblyFunction>();
+ }
+ m_size = newSize;
+ return true;
+}
+
+void JSWebAssemblyTable::clearFunction(uint32_t index)
+{
+ RELEASE_ASSERT(index < m_size);
+ m_jsFunctions.get()[index] = WriteBarrier<WebAssemblyFunction>();
+ m_functions.get()[index] = Wasm::CallableFunction();
+ ASSERT(!m_functions.get()[index].signature); // We rely on this in compiled code.
+}
+
+void JSWebAssemblyTable::setFunction(VM& vm, uint32_t index, WebAssemblyFunction* function)
+{
+ RELEASE_ASSERT(index < m_size);
+ m_jsFunctions.get()[index].set(vm, this, function);
+ m_functions.get()[index] = Wasm::CallableFunction(function->signature(), function->wasmEntrypoint());
+}
+
} // namespace JSC
#endif // ENABLE(WEBASSEMBLY)
Modified: trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/JSWebAssemblyTable.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -29,23 +29,54 @@
#include "JSDestructibleObject.h"
#include "JSObject.h"
+#include "WebAssemblyFunction.h"
+#include <wtf/MallocPtr.h>
namespace JSC {
+namespace Wasm {
+struct CallableFunction;
+}
+
class JSWebAssemblyTable : public JSDestructibleObject {
public:
typedef JSDestructibleObject Base;
- static JSWebAssemblyTable* create(VM&, Structure*);
+ static JSWebAssemblyTable* create(ExecState*, VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
DECLARE_INFO;
-protected:
- JSWebAssemblyTable(VM&, Structure*);
+ std::optional<uint32_t> maximum() const { return m_maximum; }
+ uint32_t size() const { return m_size; }
+ bool grow(uint32_t newSize) WARN_UNUSED_RETURN;
+ WebAssemblyFunction* getFunction(uint32_t index)
+ {
+ RELEASE_ASSERT(index < m_size);
+ return m_jsFunctions.get()[index].get();
+ }
+ void clearFunction(uint32_t index);
+ void setFunction(VM&, uint32_t index, WebAssemblyFunction*);
+
+ static ptrdiff_t offsetOfSize() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_size); }
+ static ptrdiff_t offsetOfFunctions() { return OBJECT_OFFSETOF(JSWebAssemblyTable, m_functions); }
+
+ static bool isValidSize(uint32_t size)
+ {
+ // This tops out at ~384 MB worth of data in this class.
+ return size < (1 << 24);
+ }
+
+private:
+ JSWebAssemblyTable(VM&, Structure*, uint32_t initial, std::optional<uint32_t> maximum);
void finishCreation(VM&);
static void destroy(JSCell*);
static void visitChildren(JSCell*, SlotVisitor&);
+
+ MallocPtr<Wasm::CallableFunction> m_functions;
+ MallocPtr<WriteBarrier<WebAssemblyFunction>> m_jsFunctions;
+ std::optional<uint32_t> m_maximum;
+ uint32_t m_size;
};
} // namespace JSC
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -117,7 +117,7 @@
JSWebAssemblyInstance* prevJSWebAssemblyInstance = vm.topJSWebAssemblyInstance;
vm.topJSWebAssemblyInstance = instance();
ASSERT(instance());
- EncodedJSValue rawResult = vmEntryToWasm(webAssemblyCallee()->entrypoint(), &vm, protoCallFrame);
+ EncodedJSValue rawResult = vmEntryToWasm(m_jsEntrypoint->entrypoint(), &vm, protoCallFrame);
vm.topJSWebAssemblyInstance = prevJSWebAssemblyInstance;
// FIXME is this correct? https://bugs.webkit.org/show_bug.cgi?id=164876
@@ -140,12 +140,12 @@
return EncodedJSValue();
}
-WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* callee, Wasm::Signature* signature)
+WebAssemblyFunction* WebAssemblyFunction::create(VM& vm, JSGlobalObject* globalObject, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
{
NativeExecutable* executable = vm.getHostFunction(callWebAssemblyFunction, NoIntrinsic, callHostFunctionAsConstructor, nullptr, name);
Structure* structure = globalObject->webAssemblyFunctionStructure();
WebAssemblyFunction* function = new (NotNull, allocateCell<WebAssemblyFunction>(vm.heap)) WebAssemblyFunction(vm, globalObject, structure);
- function->finishCreation(vm, executable, length, name, instance, callee, signature);
+ function->finishCreation(vm, executable, length, name, instance, jsEntrypoint, wasmEntrypoint, signature);
return function;
}
@@ -166,15 +166,18 @@
ASSERT_GC_OBJECT_INHERITS(thisObject, info());
Base::visitChildren(thisObject, visitor);
visitor.append(&thisObject->m_instance);
- visitor.append(&thisObject->m_wasmCallee);
+ visitor.append(&thisObject->m_jsEntrypoint);
+ visitor.append(&thisObject->m_wasmEntrypoint);
}
-void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* wasmCallee, Wasm::Signature* signature)
+void WebAssemblyFunction::finishCreation(VM& vm, NativeExecutable* executable, unsigned length, const String& name, JSWebAssemblyInstance* instance, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature* signature)
{
Base::finishCreation(vm, executable, length, name);
ASSERT(inherits(info()));
m_instance.set(vm, this, instance);
- m_wasmCallee.set(vm, this, wasmCallee);
+ ASSERT(jsEntrypoint != wasmEntrypoint);
+ m_jsEntrypoint.set(vm, this, jsEntrypoint);
+ m_wasmEntrypoint.set(vm, this, wasmEntrypoint);
m_signature = signature;
}
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyFunction.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -28,12 +28,12 @@
#if ENABLE(WEBASSEMBLY)
#include "JSFunction.h"
+#include "JSWebAssemblyCallee.h"
#include <wtf/Noncopyable.h>
namespace JSC {
class JSGlobalObject;
-class JSWebAssemblyCallee;
struct ProtoCallFrame;
class WebAssemblyInstance;
@@ -53,28 +53,29 @@
DECLARE_EXPORT_INFO;
- JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee*, Wasm::Signature*);
+ JS_EXPORT_PRIVATE static WebAssemblyFunction* create(VM&, JSGlobalObject*, unsigned, const String&, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
static Structure* createStructure(VM&, JSGlobalObject*, JSValue);
- JSWebAssemblyCallee* webAssemblyCallee() const { return m_wasmCallee.get(); }
JSWebAssemblyInstance* instance() const { return m_instance.get(); }
- const Wasm::Signature* signature()
+ Wasm::Signature* signature()
{
ASSERT(m_signature);
return m_signature;
}
EncodedJSValue call(VM&, ProtoCallFrame*);
+ void* wasmEntrypoint() { return m_wasmEntrypoint->entrypoint(); }
protected:
static void visitChildren(JSCell*, SlotVisitor&);
- void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee*, Wasm::Signature*);
+ void finishCreation(VM&, NativeExecutable*, unsigned length, const String& name, JSWebAssemblyInstance*, JSWebAssemblyCallee* jsEntrypoint, JSWebAssemblyCallee* wasmEntrypoint, Wasm::Signature*);
private:
WebAssemblyFunction(VM&, JSGlobalObject*, Structure*);
WriteBarrier<JSWebAssemblyInstance> m_instance;
- WriteBarrier<JSWebAssemblyCallee> m_wasmCallee;
+ WriteBarrier<JSWebAssemblyCallee> m_jsEntrypoint;
+ WriteBarrier<JSWebAssemblyCallee> m_wasmEntrypoint;
Wasm::Signature* m_signature;
};
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyInstanceConstructor.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -88,10 +88,10 @@
// Let imports be an initially-empty list of external values.
unsigned numImportFunctions = 0;
- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
// FIXME implement Global https://bugs.webkit.org/show_bug.cgi?id=164133
bool hasMemoryImport = false;
+ bool hasTableImport = false;
// For each import i in module.imports:
for (auto& import : moduleInformation.imports) {
// 1. Let o be the resultant value of performing Get(importObject, i.module_name).
@@ -131,12 +131,34 @@
break;
}
case Wasm::External::Table: {
+ RELEASE_ASSERT(!hasTableImport); // This should be guaranteed by a validation failure.
// 7. Otherwise (i is a table import):
- // FIXME implement Table https://bugs.webkit.org/show_bug.cgi?id=164135
+ hasTableImport = true;
+ JSWebAssemblyTable* table = jsDynamicCast<JSWebAssemblyTable*>(value);
// i. If v is not a WebAssembly.Table object, throw a TypeError.
+ if (!table)
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import is not an instance of WebAssembly.Table"))));
+
+ uint32_t expectedInitial = moduleInformation.tableInformation.initial();
+ uint32_t actualInitial = table->size();
+ if (actualInitial < expectedInitial)
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import provided an 'initial' that is too small"))));
+
+ if (std::optional<uint32_t> expectedMaximum = moduleInformation.tableInformation.maximum()) {
+ std::optional<uint32_t> actualMaximum = table->maximum();
+ if (!actualMaximum) {
+ return JSValue::encode(
+ throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Table import does not have a 'maximum' but the module requires that it does"))));
+ }
+ if (*actualMaximum > *expectedMaximum) {
+ return JSValue::encode(
+ throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("Imported Table's 'maximum' is larger than the module's expected 'maximum'"))));
+ }
+ }
+
// ii. Append v to tables.
// iii. Append v.[[Table]] to imports.
- RELEASE_ASSERT_NOT_REACHED();
+ instance->setTable(vm, table);
break;
}
case Wasm::External::Memory: {
@@ -185,7 +207,7 @@
{
if (!!moduleInformation.memory && moduleInformation.memory.isImport()) {
- // We should either have an import or we should have thrown an exception.
+ // We should either have a Memory import or we should have thrown an exception.
RELEASE_ASSERT(hasMemoryImport);
}
@@ -200,6 +222,25 @@
}
}
+ {
+ if (!!moduleInformation.tableInformation && moduleInformation.tableInformation.isImport()) {
+ // We should either have a Table import or we should have thrown an exception.
+ RELEASE_ASSERT(hasTableImport);
+ }
+
+ if (!!moduleInformation.tableInformation && !hasTableImport) {
+ RELEASE_ASSERT(!moduleInformation.tableInformation.isImport());
+ // We create a Table when it's a Table definition.
+ JSWebAssemblyTable* table = JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyMemoryStructure(),
+ moduleInformation.tableInformation.initial(), moduleInformation.tableInformation.maximum());
+ // We should always be able to allocate a JSWebAssemblyTable we've defined.
+ // If it's defined to be too large, we should have thrown a validation error.
+ ASSERT(!throwScope.exception());
+ ASSERT(table);
+ instance->setTable(vm, table);
+ }
+ }
+
moduleRecord->link(exec, instance);
RETURN_IF_EXCEPTION(throwScope, { });
if (verbose)
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyMemoryConstructor.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -30,6 +30,7 @@
#include "FunctionPrototype.h"
#include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
#include "JSWebAssemblyMemory.h"
#include "WasmMemory.h"
#include "WasmPageCount.h"
@@ -54,17 +55,6 @@
if (exec->argumentCount() != 1)
return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Memory expects exactly one argument"))));
- auto getUint32 = [&] (JSValue value) -> uint32_t {
- double doubleValue = value.toInteger(exec);
- RETURN_IF_EXCEPTION(throwScope, { });
- if (doubleValue < 0 || doubleValue > UINT_MAX) {
- throwException(exec, throwScope,
- createRangeError(exec, ASCIILiteral("WebAssembly.Memory expects the 'initial' and 'maximum' properties to be integers in the range: [0, 2^32 - 1]")));
- return 0;
- }
- return static_cast<uint32_t>(doubleValue);
- };
-
JSObject* memoryDescriptor;
{
JSValue argument = exec->argument(0);
@@ -78,7 +68,7 @@
Identifier initial = Identifier::fromString(&vm, "initial");
JSValue minSizeValue = memoryDescriptor->get(exec, initial);
RETURN_IF_EXCEPTION(throwScope, { });
- uint32_t size = getUint32(minSizeValue);
+ uint32_t size = toNonWrappingUint32(exec, minSizeValue);
RETURN_IF_EXCEPTION(throwScope, { });
if (!Wasm::PageCount::isValid(size))
return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory 'initial' page count is too large"))));
@@ -93,10 +83,10 @@
if (hasProperty) {
JSValue maxSizeValue = memoryDescriptor->get(exec, maximum);
RETURN_IF_EXCEPTION(throwScope, { });
- uint32_t size = getUint32(maxSizeValue);
+ uint32_t size = toNonWrappingUint32(exec, maxSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
if (!Wasm::PageCount::isValid(size))
return JSValue::encode(throwException(exec, throwScope, createRangeError(exec, ASCIILiteral("WebAssembly.Memory 'maximum' page count is too large"))));
- RETURN_IF_EXCEPTION(throwScope, { });
maximumPageCount = Wasm::PageCount(size);
if (initialPageCount > maximumPageCount) {
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyModuleRecord.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -77,7 +77,7 @@
break;
}
case Wasm::External::Table: {
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
break;
}
case Wasm::External::Memory: {
@@ -136,9 +136,10 @@
// a. Let func be an Exported Function Exotic Object created from c.
// b. Append func to funcs.
// c. Return func.
- JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
+ JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
+ JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(exp.functionIndex);
Wasm::Signature* signature = module->signatureForFunctionIndexSpace(exp.functionIndex);
- WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, wasmCallee, signature);
+ WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), exp.field.string(), instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
exportedValue = function;
if (hasStart && startFunctionIndexSpace == exp.functionIndex)
m_startFunction.set(vm, this, function);
@@ -145,7 +146,7 @@
break;
}
case Wasm::External::Table: {
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
+ // FIXME https://bugs.webkit.org/show_bug.cgi?id=165782
break;
}
case Wasm::External::Memory: {
@@ -174,8 +175,9 @@
// FIXME can start call imports / tables? This assumes not. https://github.com/WebAssembly/design/issues/896
if (!m_startFunction.get()) {
// The start function wasn't added above. It must be a purely internal function.
- JSWebAssemblyCallee* wasmCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
- WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, wasmCallee, signature);
+ JSWebAssemblyCallee* jsEntrypointCallee = module->jsEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
+ JSWebAssemblyCallee* wasmEntrypointCallee = module->wasmEntrypointCalleeFromFunctionIndexSpace(startFunctionIndexSpace);
+ WebAssemblyFunction* function = WebAssemblyFunction::create(vm, globalObject, signature->arguments.size(), "start", instance, jsEntrypointCallee, wasmEntrypointCallee, signature);
m_startFunction.set(vm, this, function);
}
}
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTableConstructor.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -30,6 +30,8 @@
#include "FunctionPrototype.h"
#include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
+#include "JSWebAssemblyTable.h"
#include "WebAssemblyTablePrototype.h"
#include "WebAssemblyTableConstructor.lut.h"
@@ -43,12 +45,53 @@
@end
*/
-static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyTable(ExecState* state)
+static EncodedJSValue JSC_HOST_CALL constructJSWebAssemblyTable(ExecState* exec)
{
- VM& vm = state->vm();
- auto scope = DECLARE_THROW_SCOPE(vm);
- // FIXME https://bugs.webkit.org/show_bug.cgi?id=164135
- return JSValue::encode(throwException(state, scope, createError(state, ASCIILiteral("WebAssembly doesn't yet implement the Table constructor property"))));
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSObject* memoryDescriptor;
+ {
+ JSValue argument = exec->argument(0);
+ if (!argument.isObject())
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its first argument to be an object"))));
+ memoryDescriptor = jsCast<JSObject*>(argument);
+ }
+
+ {
+ Identifier elementIdent = Identifier::fromString(&vm, "element");
+ JSValue elementValue = memoryDescriptor->get(exec, elementIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ String elementString = elementValue.toWTFString(exec);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (elementString != "anyfunc")
+ return JSValue::encode(throwException(exec, throwScope, createTypeError(exec, ASCIILiteral("WebAssembly.Table expects its 'element' field to be the string 'anyfunc'"))));
+ }
+
+ Identifier initialIdent = Identifier::fromString(&vm, "initial");
+ JSValue initialSizeValue = memoryDescriptor->get(exec, initialIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ uint32_t initial = toNonWrappingUint32(exec, initialSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ std::optional<uint32_t> maximum;
+ Identifier maximumIdent = Identifier::fromString(&vm, "maximum");
+ bool hasProperty = memoryDescriptor->hasProperty(exec, maximumIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (hasProperty) {
+ JSValue maxSizeValue = memoryDescriptor->get(exec, maximumIdent);
+ RETURN_IF_EXCEPTION(throwScope, { });
+ maximum = toNonWrappingUint32(exec, maxSizeValue);
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ if (initial > *maximum) {
+ return JSValue::encode(throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("'maximum' property must be greater than or equal to the 'initial' property"))));
+ }
+ }
+
+ throwScope.release();
+ return JSValue::encode(JSWebAssemblyTable::create(exec, vm, exec->lexicalGlobalObject()->WebAssemblyTableStructure(), initial, maximum));
}
static EncodedJSValue JSC_HOST_CALL callJSWebAssemblyTable(ExecState* state)
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.cpp 2016-12-13 20:32:40 UTC (rev 209771)
@@ -30,6 +30,8 @@
#include "FunctionPrototype.h"
#include "JSCInlines.h"
+#include "JSWebAssemblyHelpers.h"
+#include "JSWebAssemblyTable.h"
#include "WebAssemblyTablePrototype.lut.h"
@@ -42,10 +44,112 @@
@end
*/
-WebAssemblyTablePrototype* WebAssemblyTablePrototype::create(VM& vm, JSGlobalObject*, Structure* structure)
+static ALWAYS_INLINE JSWebAssemblyTable* getTable(ExecState* exec, VM& vm, JSValue v)
{
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+ JSWebAssemblyTable* result = jsDynamicCast<JSWebAssemblyTable*>(v);
+ if (!result) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("expected |this| value to be an instance of WebAssembly.Table")));
+ return nullptr;
+ }
+ return result;
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncLength(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGrow(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGet(ExecState*);
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState*);
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncLength(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+ return JSValue::encode(jsNumber(table->size()));
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGrow(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (!table->grow(index)) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("WebAssembly.Table.prototype.grow could not grow the table")));
+ return { };
+ }
+
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncGet(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+ if (index >= table->size()) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("WebAssembly.Table.prototype.get expects an integer less than the size of the table")));
+ return { };
+ }
+
+ if (WebAssemblyFunction* result = table->getFunction(index))
+ return JSValue::encode(result);
+ return JSValue::encode(jsNull());
+}
+
+EncodedJSValue JSC_HOST_CALL webAssemblyTableProtoFuncSet(ExecState* exec)
+{
+ VM& vm = exec->vm();
+ auto throwScope = DECLARE_THROW_SCOPE(vm);
+
+ JSWebAssemblyTable* table = getTable(exec, vm, exec->thisValue());
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ JSValue value = exec->argument(1);
+ WebAssemblyFunction* function = jsDynamicCast<WebAssemblyFunction*>(value);
+ if (!value.isNull() && !function) {
+ throwException(exec, throwScope,
+ createTypeError(exec, ASCIILiteral("WebAssembly.Table.prototype.set expects the second argument to be null or an instance of WebAssembly.Function")));
+ return { };
+ }
+
+ uint32_t index = toNonWrappingUint32(exec, exec->argument(0));
+ RETURN_IF_EXCEPTION(throwScope, { });
+
+ if (index >= table->size()) {
+ throwException(exec, throwScope,
+ createRangeError(exec, ASCIILiteral("WebAssembly.Table.prototype.set expects an integer less than the size of the table")));
+ return { };
+ }
+
+ if (value.isNull())
+ table->clearFunction(index);
+ else {
+ ASSERT(!!function);
+ table->setFunction(vm, index, function);
+ }
+
+ return JSValue::encode(jsUndefined());
+}
+
+WebAssemblyTablePrototype* WebAssemblyTablePrototype::create(VM& vm, JSGlobalObject* globalObject, Structure* structure)
+{
auto* object = new (NotNull, allocateCell<WebAssemblyTablePrototype>(vm.heap)) WebAssemblyTablePrototype(vm, structure);
- object->finishCreation(vm);
+ object->finishCreation(vm, globalObject);
return object;
}
@@ -54,9 +158,14 @@
return Structure::create(vm, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), info());
}
-void WebAssemblyTablePrototype::finishCreation(VM& vm)
+void WebAssemblyTablePrototype::finishCreation(VM& vm, JSGlobalObject* globalObject)
{
Base::finishCreation(vm);
+
+ JSC_NATIVE_GETTER("length", webAssemblyTableProtoFuncLength, DontEnum | Accessor);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("grow", webAssemblyTableProtoFuncGrow, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("get", webAssemblyTableProtoFuncGet, DontEnum, 1);
+ JSC_NATIVE_FUNCTION_WITHOUT_TRANSITION("set", webAssemblyTableProtoFuncSet, DontEnum, 2);
}
WebAssemblyTablePrototype::WebAssemblyTablePrototype(VM& vm, Structure* structure)
Modified: trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.h (209770 => 209771)
--- trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.h 2016-12-13 20:24:11 UTC (rev 209770)
+++ trunk/Source/_javascript_Core/wasm/js/WebAssemblyTablePrototype.h 2016-12-13 20:32:40 UTC (rev 209771)
@@ -43,7 +43,7 @@
DECLARE_INFO;
protected:
- void finishCreation(VM&);
+ void finishCreation(VM&, JSGlobalObject*);
private:
WebAssemblyTablePrototype(VM&, Structure*);