6b650574fc
This CL just adds a parameter to addElementSegment and adjusts all existing tests. Note that addElementSegment contains some convenience code to construct one initial table if it does not exist yet. I did not extend that code to multiple tables. If you want to use multiple tables, you have to create them first before calling addElementSegment. R=clemensh@chromium.org Bug: v8:7581 Change-Id: Ie131fd5dc19856703ab5cfb2fa8f7d576f70a18b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1520709 Reviewed-by: Clemens Hammacher <clemensh@chromium.org> Reviewed-by: Andreas Haas <ahaas@chromium.org> Commit-Queue: Andreas Haas <ahaas@chromium.org> Cr-Commit-Position: refs/heads/master@{#60211}
898 lines
28 KiB
JavaScript
898 lines
28 KiB
JavaScript
// Copyright 2016 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// Flags: --expose-wasm --expose-gc
|
|
|
|
load("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
function AddFunctions(builder) {
|
|
let sig_index = builder.addType(kSig_i_ii);
|
|
let mul = builder.addFunction("mul", sig_index)
|
|
.addBody([
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprI32Mul // --
|
|
]);
|
|
let add = builder.addFunction("add", sig_index)
|
|
.addBody([
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprI32Add // --
|
|
]);
|
|
let sub = builder.addFunction("sub", sig_index)
|
|
.addBody([
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprI32Sub // --
|
|
]);
|
|
return {mul: mul, add: add, sub: sub};
|
|
}
|
|
|
|
function js_div(a, b) { return (a / b) | 0; }
|
|
|
|
(function ExportedTableTest() {
|
|
print(arguments.callee.name);
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let d = builder.addImport("q", "js_div", kSig_i_ii);
|
|
let f = AddFunctions(builder);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 33, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
f.add.exportAs("blarg");
|
|
|
|
builder.setTableBounds(10, 10);
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
builder.addElementSegment(
|
|
0, g, true, [f.mul.index, f.add.index, f.sub.index, d]);
|
|
builder.addExportOfKind("table", kExternalTable, 0);
|
|
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
for (let i = 0; i < 5; i++) {
|
|
print(" base = " + i);
|
|
let instance = new WebAssembly.Instance(module, {q: {base: i, js_div: js_div}});
|
|
main = instance.exports.main;
|
|
let table = instance.exports.table;
|
|
assertTrue(table instanceof WebAssembly.Table);
|
|
assertEquals(10, table.length);
|
|
for (let j = 0; j < i; j++) {
|
|
assertSame(null, table.get(j));
|
|
}
|
|
let mul = table.get(i+0);
|
|
let add = table.get(i+1);
|
|
let sub = table.get(i+2);
|
|
|
|
print(" mul=" + mul);
|
|
print(" add=" + add);
|
|
print(" sub=" + sub);
|
|
assertEquals("function", typeof mul);
|
|
assertEquals("function", typeof add);
|
|
assertEquals("function", typeof sub);
|
|
assertEquals(2, mul.length);
|
|
assertEquals(2, add.length);
|
|
assertEquals(2, sub.length);
|
|
assertEquals(String(f.add.index), add.name);
|
|
|
|
let exp_div = table.get(i+3);
|
|
assertEquals("function", typeof exp_div);
|
|
print(" js_div=" + exp_div);
|
|
// Should have a new, wrapped version of the import.
|
|
assertFalse(js_div == exp_div);
|
|
|
|
|
|
for (let j = i + 4; j < 10; j++) {
|
|
assertSame(null, table.get(j));
|
|
}
|
|
|
|
assertEquals(-33, mul(-11, 3));
|
|
assertEquals(4444444, add(3333333, 1111111));
|
|
assertEquals(-9999, sub(1, 10000));
|
|
assertEquals(-44, exp_div(-88.1, 2));
|
|
}
|
|
})();
|
|
|
|
|
|
(function ImportedTableTest1() {
|
|
let kTableSize = 10;
|
|
print(arguments.callee.name);
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
let d = builder.addImport("q", "js_div", kSig_i_ii);
|
|
let f = AddFunctions(builder);
|
|
builder.setTableBounds(kTableSize, kTableSize);
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
builder.addElementSegment(
|
|
0, g, true, [f.mul.index, f.add.index, f.sub.index, d]);
|
|
builder.addExportOfKind("table", kExternalTable, 0);
|
|
|
|
let m1 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.addImportedTable("r", "table", kTableSize, kTableSize);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 33, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
let m2 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
// Run 5 trials at different table bases.
|
|
for (let i = 0; i < 5; i++) {
|
|
print(" base = " + i);
|
|
let i1 = new WebAssembly.Instance(m1, {q: {base: i, js_div: js_div}});
|
|
let table = i1.exports.table;
|
|
assertEquals(10, table.length);
|
|
let i2 = new WebAssembly.Instance(m2, {r: {table: table}});
|
|
let main = i2.exports.main;
|
|
|
|
for (var j = 0; j < i; j++) {
|
|
assertTraps(kTrapFuncSigMismatch, () => main(0, j));
|
|
assertSame(null, table.get(j));
|
|
}
|
|
|
|
// mul
|
|
assertEquals("function", typeof table.get(i+0));
|
|
assertEquals(0, main(0, i+0));
|
|
assertEquals(66, main(2, i+0));
|
|
|
|
// add
|
|
assertEquals("function", typeof table.get(i+1));
|
|
assertEquals(33, main(0, i+1));
|
|
assertEquals(38, main(5, i+1));
|
|
|
|
// sub
|
|
assertEquals("function", typeof table.get(i+2));
|
|
assertEquals(32, main(1, i+2));
|
|
assertEquals(28, main(5, i+2));
|
|
|
|
// div
|
|
assertEquals("function", typeof table.get(i+3));
|
|
assertEquals(8, main(4, i+3));
|
|
assertEquals(3, main(11, i+3));
|
|
|
|
for (var j = i + 4; j < (kTableSize + 5); j++) {
|
|
assertThrows(x => main(0, j));
|
|
if (j < kTableSize) assertSame(null, table.get(j));
|
|
}
|
|
}
|
|
})();
|
|
|
|
(function ImportedTableTest2() {
|
|
let kTableSize = 10;
|
|
print(arguments.callee.name);
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
let d = builder.addImport("q", "js_div", kSig_i_ii);
|
|
builder.addImportedTable("q", "table", kTableSize, kTableSize);
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
let f = AddFunctions(builder);
|
|
builder.addElementSegment(
|
|
0, g, true, [f.mul.index, f.add.index, f.sub.index, d]);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 55, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
let m2 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
// Run 5 trials at different table bases.
|
|
for (let i = 0; i < 5; i++) {
|
|
print(" base = " + i);
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
initial: kTableSize,
|
|
maximum: kTableSize});
|
|
assertEquals(10, table.length);
|
|
let i2 = new WebAssembly.Instance(m2, {q: {base: i, table: table,
|
|
js_div: js_div}});
|
|
let main = i2.exports.main;
|
|
|
|
for (var j = 0; j < i; j++) {
|
|
assertTraps(kTrapFuncSigMismatch, () => main(0, j));
|
|
assertSame(null, table.get(j));
|
|
}
|
|
|
|
// mul
|
|
assertEquals("function", typeof table.get(i+0));
|
|
assertEquals(0, main(0, i+0));
|
|
assertEquals(110, main(2, i+0));
|
|
|
|
// add
|
|
assertEquals("function", typeof table.get(i+1));
|
|
assertEquals(55, main(0, i+1));
|
|
assertEquals(60, main(5, i+1));
|
|
|
|
// sub
|
|
assertEquals("function", typeof table.get(i+2));
|
|
assertEquals(54, main(1, i+2));
|
|
assertEquals(50, main(5, i+2));
|
|
|
|
// div
|
|
assertEquals("function", typeof table.get(i+3));
|
|
assertEquals(13, main(4, i+3));
|
|
assertEquals(5, main(11, i+3));
|
|
|
|
for (var j = i + 4; j < (kTableSize + 5); j++) {
|
|
assertThrows(x => main(0, j));
|
|
if (j < kTableSize) assertSame(null, table.get(j));
|
|
}
|
|
}
|
|
})();
|
|
|
|
|
|
(function CumulativeTest() {
|
|
print(arguments.callee.name);
|
|
|
|
let kTableSize = 10;
|
|
let table = new WebAssembly.Table(
|
|
{element: "anyfunc", initial: kTableSize, maximum: kTableSize});
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.addImportedTable("x", "table", kTableSize, kTableSize);
|
|
let g = builder.addImportedGlobal("x", "base", kWasmI32);
|
|
let sig_index = builder.addType(kSig_i_v);
|
|
let f = builder.addFunction("f", sig_index)
|
|
.addBody([
|
|
kExprGetGlobal, g
|
|
]);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprCallIndirect, sig_index, kTableZero]) // --
|
|
.exportAs("main");
|
|
builder.addElementSegment(0, g, true, [f.index]);
|
|
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
for (var i = 0; i < kTableSize; i++) {
|
|
print(" base = " + i);
|
|
let instance = new WebAssembly.Instance(module, {x: {base: i, table: table}});
|
|
|
|
for (var j = 0; j < kTableSize; j++) {
|
|
let func = table.get(j);
|
|
if (j > i) {
|
|
assertSame(null, func);
|
|
assertTraps(kTrapFuncSigMismatch, () => instance.exports.main(j));
|
|
} else {
|
|
assertEquals("function", typeof func);
|
|
assertEquals(j, func());
|
|
assertEquals(j, instance.exports.main(j));
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
|
|
(function TwoWayTest() {
|
|
print(arguments.callee.name);
|
|
let kTableSize = 3;
|
|
|
|
// Module {m1} defines the table and exports it.
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addType(kSig_i_i);
|
|
builder.addType(kSig_i_ii);
|
|
var sig_index1 = builder.addType(kSig_i_v);
|
|
var f1 = builder.addFunction("f1", sig_index1)
|
|
.addBody([kExprI32Const, 11]);
|
|
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprGetLocal, 0, // --
|
|
kExprCallIndirect, sig_index1, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
builder.setTableBounds(kTableSize, kTableSize);
|
|
builder.addElementSegment(0, 0, false, [f1.index]);
|
|
builder.addExportOfKind("table", kExternalTable, 0);
|
|
|
|
var m1 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
// Module {m2} imports the table and adds {f2}.
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addType(kSig_i_ii);
|
|
var sig_index2 = builder.addType(kSig_i_v);
|
|
var f2 = builder.addFunction("f2", sig_index2)
|
|
.addBody([kExprI32Const, 22]);
|
|
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprGetLocal, 0, // --
|
|
kExprCallIndirect, sig_index2, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
builder.addImportedTable("z", "table", kTableSize, kTableSize);
|
|
builder.addElementSegment(0, 1, false, [f2.index], true);
|
|
|
|
var m2 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
assertFalse(sig_index1 == sig_index2);
|
|
|
|
var i1 = new WebAssembly.Instance(m1);
|
|
var i2 = new WebAssembly.Instance(m2, {z: {table: i1.exports.table}});
|
|
|
|
assertEquals(11, i1.exports.main(0));
|
|
assertEquals(11, i2.exports.main(0));
|
|
|
|
assertEquals(22, i1.exports.main(1));
|
|
assertEquals(22, i2.exports.main(1));
|
|
|
|
assertTraps(kTrapFuncSigMismatch, () => i1.exports.main(2));
|
|
assertTraps(kTrapFuncSigMismatch, () => i2.exports.main(2));
|
|
assertTraps(kTrapFuncInvalid, () => i1.exports.main(3));
|
|
assertTraps(kTrapFuncInvalid, () => i2.exports.main(3));
|
|
})();
|
|
|
|
(function MismatchedTableSize() {
|
|
print(arguments.callee.name);
|
|
let kTableSize = 5;
|
|
|
|
for (var expsize = 1; expsize < 4; expsize++) {
|
|
for (var impsize = 1; impsize < 4; impsize++) {
|
|
print(" expsize = " + expsize + ", impsize = " + impsize);
|
|
var builder = new WasmModuleBuilder();
|
|
builder.setTableBounds(expsize, expsize);
|
|
builder.addExportOfKind("expfoo", kExternalTable, 0);
|
|
|
|
let m1 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("y", "impfoo", impsize, impsize);
|
|
|
|
let m2 = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
var i1 = new WebAssembly.Instance(m1);
|
|
|
|
// TODO(titzer): v8 currently requires import table size to match
|
|
// export table size.
|
|
var ffi = {y: {impfoo: i1.exports.expfoo}};
|
|
if (expsize == impsize) {
|
|
var i2 = new WebAssembly.Instance(m2, ffi);
|
|
} else {
|
|
assertThrows(() => new WebAssembly.Instance(m2, ffi));
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
|
|
(function TableGrowBoundsCheck() {
|
|
print(arguments.callee.name);
|
|
var kMaxSize = 30, kInitSize = 5;
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
initial: kInitSize, maximum: kMaxSize});
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("x", "table", kInitSize, kMaxSize);
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
let instance = new WebAssembly.Instance(module, {x: {base: 1, table: table}});
|
|
|
|
for(var i = kInitSize; i < kMaxSize; i+=5) {
|
|
assertEquals(i, table.length);
|
|
for (var j = 0; j < i; j++) table.set(j, null);
|
|
for (var j = 0; j < i; j++) assertEquals(null, table.get(j));
|
|
assertThrows(() => table.set(i, null), RangeError);
|
|
assertThrows(() => table.get(i), RangeError);
|
|
assertEquals(i, table.grow(5));
|
|
}
|
|
assertEquals(30, table.length);
|
|
assertThrows(() => table.grow(1), RangeError);
|
|
assertThrows(() => table.set(kMaxSize, null), RangeError);
|
|
assertThrows(() => table.get(kMaxSize), RangeError);
|
|
})();
|
|
|
|
(function CumulativeGrowTest() {
|
|
print(arguments.callee.name);
|
|
let table = new WebAssembly.Table({
|
|
element: "anyfunc", initial: 10, maximum: 30});
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("x", "table", 10, 30);
|
|
|
|
let g = builder.addImportedGlobal("x", "base", kWasmI32);
|
|
let sig_index = builder.addType(kSig_i_v);
|
|
builder.addFunction("g", sig_index)
|
|
.addBody([
|
|
kExprGetGlobal, g
|
|
]);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprCallIndirect, sig_index, kTableZero]) // --
|
|
.exportAs("main");
|
|
builder.addElementSegment(0, g, true, [g]);
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
var instances = [];
|
|
for (var i = 0; i < 10; i++) {
|
|
print(" base = " + i);
|
|
instances.push(new WebAssembly.Instance(
|
|
module, {x: {base: i, table: table}}));
|
|
}
|
|
|
|
for (var j = 0; j < 10; j++) {
|
|
let func = table.get(j);
|
|
assertEquals("function", typeof func);
|
|
assertEquals(j, func());
|
|
assertEquals(j, instances[j].exports.main(j));
|
|
}
|
|
|
|
assertEquals(10, table.grow(10));
|
|
|
|
// Verify that grow does not alter function behaviors
|
|
for (var j = 0; j < 10; j++) {
|
|
let func = table.get(j);
|
|
assertEquals("function", typeof func);
|
|
assertEquals(j, func());
|
|
assertEquals(j, instances[j].exports.main(j));
|
|
}
|
|
|
|
let new_builder = new WasmModuleBuilder();
|
|
new_builder.addExport("wasm", new_builder.addFunction("", kSig_v_v).addBody([]));
|
|
new_builder.addImportedTable("x", "table", 20, 30);
|
|
let new_module = new WebAssembly.Module(new_builder.toBuffer());
|
|
let instance = new WebAssembly.Instance(new_module, {x: {table: table}});
|
|
let new_func = instance.exports.wasm;
|
|
|
|
for (var j = 10; j < 20; j++) {
|
|
table.set(j, new_func);
|
|
let func = table.get(j);
|
|
assertEquals("function", typeof func);
|
|
assertSame(new_func, table.get(j));
|
|
}
|
|
assertThrows(() => table.grow(11), RangeError);
|
|
})();
|
|
|
|
|
|
(function TestImportTooLarge() {
|
|
print(arguments.callee.name);
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("t", "t", 1, 2);
|
|
|
|
// initial size is too large
|
|
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
|
|
{element: "anyfunc", initial: 3, maximum: 3})}}), WebAssembly.LinkError);
|
|
|
|
// maximum size is too large
|
|
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
|
|
{element: "anyfunc", initial: 1, maximum: 4})}}), WebAssembly.LinkError);
|
|
|
|
// no maximum
|
|
assertThrows(() => builder.instantiate({t: {t: new WebAssembly.Table(
|
|
{element: "anyfunc", initial: 1})}}), WebAssembly.LinkError);
|
|
})();
|
|
|
|
(function TableImportLargerThanCompiled() {
|
|
print(arguments.callee.name);
|
|
var kMaxSize = 30, kInitSize = 5;
|
|
var builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("x", "table", 1, 35);
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
initial: kInitSize, maximum: kMaxSize});
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
let instance = new WebAssembly.Instance(module, {x: {base: 1, table: table}});
|
|
for (var i = 0; i < kInitSize; ++i) table.set(i, null);
|
|
for (var i = 0; i < kInitSize; ++i) assertEquals(null, table.get(i));
|
|
assertThrows(() => table.set(kInitSize, null), RangeError);
|
|
})();
|
|
|
|
(function ModulesShareTableAndGrow() {
|
|
print(arguments.callee.name);
|
|
let module1 = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("x", "table", 1, 35);
|
|
return new WebAssembly.Module(builder.toBuffer());
|
|
})();
|
|
let module2 = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("x", "table", 2, 40);
|
|
return new WebAssembly.Module(builder.toBuffer());
|
|
})();
|
|
|
|
var kMaxSize = 30, kInitSize = 5;
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
initial: kInitSize, maximum: kMaxSize});
|
|
let instance1 = new WebAssembly.Instance(
|
|
module1, {x: {base: 1, table: table}});
|
|
let instance2 = new WebAssembly.Instance(
|
|
module2, {x: {base: 1, table: table}});
|
|
|
|
for (var i = 0; i < kInitSize; ++i) table.set(i, null);
|
|
for (var i = 0; i < kInitSize; ++i) assertEquals(null, table.get(i));
|
|
assertThrows(() => table.set(kInitSize, null), RangeError);
|
|
assertEquals(kInitSize, table.grow(5));
|
|
for (var i = 0; i < 2*kInitSize; ++i) table.set(i, null);
|
|
for (var i = 0; i < 2*kInitSize; ++i) assertEquals(null, table.get(i));
|
|
assertThrows(() => table.set(2*kInitSize, null), RangeError);
|
|
// Try to grow past imported maximum
|
|
assertThrows(() => table.grow(21), RangeError);
|
|
})();
|
|
|
|
(function MultipleElementSegments() {
|
|
let kTableSize = 10;
|
|
print(arguments.callee.name);
|
|
|
|
let mul = (a, b) => a * b;
|
|
let add = (a, b) => a + b;
|
|
let sub = (a, b) => a - b;
|
|
|
|
// Test 1 to 3 segments in the elements section.
|
|
// segment 1 sets [1, 2] to mul,
|
|
// segment 2 sets [2, 3, 4] to add,
|
|
// segment 3 sets [3, 4, 5, 6] to sub.
|
|
for (let num_segments = 1; num_segments < 4; ++num_segments) {
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
builder.setTableBounds(kTableSize, kTableSize);
|
|
builder.addExportOfKind("table", kExternalTable, 0);
|
|
let f = AddFunctions(builder);
|
|
let indexes = [f.mul.index, f.add.index, f.sub.index];
|
|
for (let i = 0; i < num_segments; ++i) {
|
|
let offset = i + 1;
|
|
let len = i + 2;
|
|
let index = indexes[i];
|
|
builder.addElementSegment(0, offset, false, new Array(len).fill(index));
|
|
}
|
|
|
|
let instance = builder.instantiate();
|
|
|
|
let table = instance.exports.table;
|
|
assertEquals(kTableSize, table.length);
|
|
|
|
for (let i = 0; i < num_segments; ++i) {
|
|
let exp = i < 1 || i > 2 ? null : mul;
|
|
if (num_segments > 1 && i >= 2 && i <= 4) exp = add;
|
|
if (num_segments > 2 && i >= 3 && i <= 6) exp = sub;
|
|
if (!exp) {
|
|
assertSame(null, table.get(i));
|
|
} else {
|
|
assertEquals("function", typeof table.get(i));
|
|
assertEquals(exp(6, 3), table.get(i)(6, 3));
|
|
}
|
|
}
|
|
}
|
|
})();
|
|
|
|
(function InitImportedTableSignatureMismatch() {
|
|
// instance0 exports a function table and a main function which indirectly
|
|
// calls a function from the table.
|
|
let builder0 = new WasmModuleBuilder();
|
|
builder0.setName('module_0');
|
|
let sig_index = builder0.addType(kSig_i_v);
|
|
builder0.addFunction('main', kSig_i_i)
|
|
.addBody([
|
|
kExprGetLocal, 0, // -
|
|
kExprCallIndirect, sig_index, kTableZero
|
|
])
|
|
.exportAs('main');
|
|
builder0.setTableBounds(3, 3);
|
|
builder0.addExportOfKind('table', kExternalTable);
|
|
let module0 = new WebAssembly.Module(builder0.toBuffer());
|
|
let instance0 = new WebAssembly.Instance(module0);
|
|
|
|
// instance1 imports the table and adds a function to it.
|
|
let builder1 = new WasmModuleBuilder();
|
|
builder1.setName('module_1');
|
|
builder1.addFunction('f', kSig_i_i).addBody([kExprGetLocal, 0]);
|
|
builder1.addImportedTable('z', 'table');
|
|
builder1.addElementSegment(0, 0, false, [0], true);
|
|
let module1 = new WebAssembly.Module(builder1.toBuffer());
|
|
let instance1 =
|
|
new WebAssembly.Instance(module1, {z: {table: instance0.exports.table}});
|
|
|
|
// Calling the main method on instance0 should fail, because the signature of
|
|
// the added function does not match.
|
|
assertThrows(
|
|
() => instance0.exports.main(0), WebAssembly.RuntimeError,
|
|
/signature mismatch/);
|
|
})();
|
|
|
|
(function IndirectCallIntoOtherInstance() {
|
|
print(arguments.callee.name);
|
|
|
|
var mem_1 = new WebAssembly.Memory({initial: 1});
|
|
var mem_2 = new WebAssembly.Memory({initial: 1});
|
|
var view_1 = new Int32Array(mem_1.buffer);
|
|
var view_2 = new Int32Array(mem_2.buffer);
|
|
view_1[0] = 1;
|
|
view_2[0] = 1000;
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
let sig = builder.addType(kSig_i_v);
|
|
builder.addFunction('main', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, kExprCallIndirect, sig, kTableZero])
|
|
.exportAs('main');
|
|
builder.addImportedMemory('', 'memory', 1);
|
|
|
|
builder.setTableBounds(1, 1);
|
|
builder.addExportOfKind('table', kExternalTable);
|
|
|
|
let module1 = new WebAssembly.Module(builder.toBuffer());
|
|
let instance1 = new WebAssembly.Instance(module1, {'':{memory:mem_1}});
|
|
|
|
builder = new WasmModuleBuilder();
|
|
builder.addFunction('main', kSig_i_v).addBody([kExprI32Const, 0, kExprI32LoadMem, 0, 0]);
|
|
builder.addImportedTable('', 'table');
|
|
builder.addElementSegment(0, 0, false, [0], true);
|
|
builder.addImportedMemory('', 'memory', 1);
|
|
|
|
|
|
let module2 = new WebAssembly.Module(builder.toBuffer());
|
|
let instance2 = new WebAssembly.Instance(module2, {
|
|
'': {
|
|
table: instance1.exports.table,
|
|
memory: mem_2
|
|
}
|
|
});
|
|
|
|
assertEquals(instance1.exports.main(0), 1000);
|
|
})();
|
|
|
|
|
|
(function ImportedFreestandingTable() {
|
|
print(arguments.callee.name);
|
|
|
|
function forceGc() {
|
|
gc();
|
|
gc();
|
|
gc();
|
|
}
|
|
|
|
function setup() {
|
|
let builder = new WasmModuleBuilder();
|
|
let sig = builder.addType(kSig_i_v);
|
|
builder.addFunction('main', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, kExprCallIndirect, sig, kTableZero])
|
|
.exportAs('main');
|
|
|
|
builder.addImportedTable('', 'table');
|
|
|
|
let module1 = new WebAssembly.Module(builder.toBuffer());
|
|
let table = new WebAssembly.Table({initial:2, element:'anyfunc'});
|
|
let instance1 = new WebAssembly.Instance(module1, {'':{table: table}});
|
|
|
|
builder = new WasmModuleBuilder();
|
|
builder.addExport('theImport', builder.addImport('', 'callout', kSig_i_v));
|
|
builder.addImportedMemory('', 'memory', 1);
|
|
builder.addFunction('main', kSig_i_v)
|
|
.addBody([
|
|
kExprCallFunction, 0,
|
|
kExprI32Const, 0, kExprI32LoadMem, 0, 0,
|
|
kExprI32Add
|
|
]).exportAs('main');
|
|
|
|
let mem = new WebAssembly.Memory({initial:1});
|
|
let view = new Int32Array(mem.buffer);
|
|
view[0] = 4;
|
|
|
|
let module2 = new WebAssembly.Module(builder.toBuffer());
|
|
let instance2 = new WebAssembly.Instance(module2, {
|
|
'': {
|
|
callout: () => {
|
|
forceGc();
|
|
return 3;
|
|
},
|
|
'memory': mem
|
|
}
|
|
});
|
|
table.set(0, instance2.exports.main);
|
|
table.set(1, instance2.exports.theImport);
|
|
return instance1;
|
|
}
|
|
|
|
function test(variant, expectation) {
|
|
var instance = setup();
|
|
forceGc();
|
|
assertEquals(expectation, instance.exports.main(variant));
|
|
}
|
|
|
|
// 0 indirectly calls the wasm function that calls the import,
|
|
// 1 does the same but for the exported import.
|
|
test(0, 7);
|
|
test(1, 3);
|
|
})();
|
|
|
|
|
|
(function ImportedWasmFunctionPutIntoTable() {
|
|
print(arguments.callee.name);
|
|
|
|
let wasm_mul = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction("mul", kSig_i_ii)
|
|
.addBody(
|
|
[kExprGetLocal, 0,
|
|
kExprGetLocal, 1,
|
|
kExprI32Mul])
|
|
.exportFunc();
|
|
return builder.instantiate().exports.mul;
|
|
})();
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let j = builder.addImport("q", "js_div", kSig_i_ii);
|
|
let w = builder.addImport("q", "wasm_mul", kSig_i_ii);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 33, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
builder.setTableBounds(10, 10);
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
builder.addElementSegment(0, g, true, [j, w]);
|
|
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
for (var i = 0; i < 5; i++) {
|
|
let instance = new WebAssembly.Instance(module, {q: {base: i, js_div: js_div, wasm_mul: wasm_mul}});
|
|
let j = i + 1;
|
|
|
|
assertThrows(() => {instance.exports.main(j, i-1)});
|
|
assertEquals((33/j)|0, instance.exports.main(j, i+0));
|
|
assertEquals((33*j)|0, instance.exports.main(j, i+1));
|
|
assertThrows(() => {instance.exports.main(j, i+2)});
|
|
}
|
|
|
|
})();
|
|
|
|
(function ImportedWasmFunctionPutIntoImportedTable() {
|
|
print(arguments.callee.name);
|
|
|
|
let kTableSize = 10;
|
|
|
|
let wasm_mul = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction("mul", kSig_i_ii)
|
|
.addBody(
|
|
[kExprGetLocal, 0,
|
|
kExprGetLocal, 1,
|
|
kExprI32Mul])
|
|
.exportFunc();
|
|
return builder.instantiate().exports.mul;
|
|
})();
|
|
|
|
let table = new WebAssembly.Table({element: "anyfunc",
|
|
initial: kTableSize,
|
|
maximum: kTableSize});
|
|
|
|
let builder = new WasmModuleBuilder();
|
|
|
|
let j = builder.addImport("q", "js_div", kSig_i_ii);
|
|
let w = builder.addImport("q", "wasm_mul", kSig_i_ii);
|
|
builder.addImportedTable("q", "table", kTableSize, kTableSize);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 44, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, kTableZero]) // --
|
|
.exportAs("main");
|
|
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
builder.addElementSegment(0, g, true, [j, w]);
|
|
|
|
let module = new WebAssembly.Module(builder.toBuffer());
|
|
for (var i = 0; i < 5; i++) {
|
|
let instance = new WebAssembly.Instance(module, {q: {base: i, js_div: js_div, wasm_mul: wasm_mul, table: table}});
|
|
let j = i + 1;
|
|
|
|
assertEquals((44/j)|0, instance.exports.main(j, i+0));
|
|
assertEquals((44*j)|0, instance.exports.main(j, i+1));
|
|
assertThrows(() => {instance.exports.main(j, i+2)});
|
|
}
|
|
})();
|
|
|
|
(function ExportedFunctionsImportedOrder() {
|
|
print(arguments.callee.name);
|
|
|
|
let i1 = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addFunction("f1", kSig_i_v)
|
|
.addBody(
|
|
[kExprI32Const, 1])
|
|
.exportFunc();
|
|
builder.addFunction("f2", kSig_i_v)
|
|
.addBody(
|
|
[kExprI32Const, 2])
|
|
.exportFunc();
|
|
return builder.instantiate();
|
|
})();
|
|
|
|
let i2 = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addImport("q", "f2", kSig_i_v);
|
|
builder.addImport("q", "f1", kSig_i_v);
|
|
builder.addFunction("main", kSig_i_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprCallIndirect, 0, kTableZero
|
|
])
|
|
.exportFunc();
|
|
builder.addElementSegment(0, 0, false, [0, 1, 1, 0]);
|
|
|
|
return builder.instantiate({q: {f2: i1.exports.f2, f1: i1.exports.f1}});
|
|
})();
|
|
|
|
assertEquals(2, i2.exports.main(0));
|
|
assertEquals(1, i2.exports.main(1));
|
|
assertEquals(1, i2.exports.main(2));
|
|
assertEquals(2, i2.exports.main(3));
|
|
})();
|
|
|
|
(function IndirectCallsToImportedFunctions() {
|
|
print(arguments.callee.name);
|
|
|
|
let module = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 1, false);
|
|
builder.addFunction("f", kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 0,
|
|
kExprI32LoadMem, 0, 4,
|
|
])
|
|
.exportFunc();
|
|
builder.exportMemoryAs("memory");
|
|
return new WebAssembly.Module(builder.toBuffer());
|
|
})();
|
|
|
|
function setMemI32(instance, offset, val) {
|
|
var array = new Int32Array(instance.exports.memory.buffer);
|
|
array[offset/4] = val;
|
|
}
|
|
|
|
function makeFun(val) {
|
|
let instance = new WebAssembly.Instance(module);
|
|
setMemI32(instance, 0, 2000000);
|
|
setMemI32(instance, 4, val);
|
|
setMemI32(instance, 8, 3000000);
|
|
return instance.exports.f;
|
|
}
|
|
|
|
let f300 = makeFun(300);
|
|
let f100 = makeFun(100);
|
|
let f200 = makeFun(200);
|
|
|
|
let main = (() => {
|
|
let builder = new WasmModuleBuilder();
|
|
builder.addMemory(1, 1, false);
|
|
builder.addImport("q", "f1", kSig_i_v);
|
|
builder.addImport("q", "f2", kSig_i_v);
|
|
builder.addImport("q", "f3", kSig_i_v);
|
|
builder.addFunction("f", kSig_i_v)
|
|
.addBody([
|
|
kExprI32Const, 8,
|
|
kExprI32LoadMem, 0, 0,
|
|
]);
|
|
builder.addFunction("main", kSig_i_i)
|
|
.addBody([
|
|
kExprGetLocal, 0,
|
|
kExprCallIndirect, 0, kTableZero
|
|
])
|
|
.exportFunc();
|
|
builder.exportMemoryAs("memory");
|
|
builder.addElementSegment(0, 0, false, [0, 1, 2, 3]);
|
|
var instance = builder.instantiate({q: {f1: f100, f2: f200, f3: f300}});
|
|
setMemI32(instance, 0, 5000000);
|
|
setMemI32(instance, 4, 6000000);
|
|
setMemI32(instance, 8, 400);
|
|
return instance.exports.main;
|
|
})();
|
|
|
|
assertEquals(100, main(0));
|
|
assertEquals(200, main(1));
|
|
assertEquals(300, main(2));
|
|
assertEquals(400, main(3));
|
|
})();
|