2d9ec0a420
The reason for the revert was that Liftoff did not bail out on indirect calls to tables other than table 0. Whenever the Liftoff code got executed, the test would fail. Original message: With this CL it is possible to use any anyfunc table in call-indirect, not just the first table. The current implementation is based on runtime calls. This is just an initial implementation which should be replaced by a dispatch-table-based eventually. However, this implementation allows us to move forward with the anyref proposal implementation. R=mstarzinger@chromium.org Bug: v8:7581 Change-Id: Iedd56ee7acb281441bca32ffd3dc7157203ee1ac Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1532072 Commit-Queue: Andreas Haas <ahaas@chromium.org> Auto-Submit: Andreas Haas <ahaas@chromium.org> Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Cr-Commit-Position: refs/heads/master@{#60382}
203 lines
7.0 KiB
JavaScript
203 lines
7.0 KiB
JavaScript
// Copyright 2019 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 --experimental-wasm-anyref --experimental-wasm-return-call
|
|
|
|
load("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
(function IndirectCallToNonZeroTable() {
|
|
print(arguments.callee.name);
|
|
|
|
const builder = new WasmModuleBuilder();
|
|
const placeholder = builder.addTable(kWasmAnyFunc, 3).index;
|
|
const table1 = builder.addTable(kWasmAnyFunc, 3).index;
|
|
const table2 = builder.addTable(kWasmAnyFunc, 5).index;
|
|
const sig_index = builder.addType(kSig_i_v);
|
|
const other_sig = builder.addType(kSig_i_i);
|
|
|
|
const v1 = 16;
|
|
const v2 = 26;
|
|
const v3 = 36;
|
|
const v4 = 46;
|
|
const v5 = 56;
|
|
|
|
const f_unreachable = builder.addFunction('unreachable', sig_index)
|
|
.addBody([kExprUnreachable]).index;
|
|
const f1 = builder.addFunction('f1', sig_index)
|
|
.addBody([kExprI32Const, v1])
|
|
.index;
|
|
const f2 = builder.addFunction('f2', sig_index)
|
|
.addBody([kExprI32Const, v2])
|
|
.index;
|
|
const f3 = builder.addFunction('f3', sig_index)
|
|
.addBody([kExprI32Const, v3])
|
|
.index;
|
|
const f4 = builder.addFunction('f4', sig_index)
|
|
.addBody([kExprI32Const, v4])
|
|
.index;
|
|
const f5 = builder.addFunction('f5', sig_index)
|
|
.addBody([kExprI32Const, v5])
|
|
.index;
|
|
|
|
builder.addFunction('call1', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, // function index
|
|
kExprCallIndirect, sig_index, table1])
|
|
.exportAs('call1');
|
|
builder.addFunction('return_call1', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, // function index
|
|
kExprReturnCallIndirect, sig_index, table1])
|
|
.exportAs('return_call1');
|
|
builder.addFunction('call2', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, // function index
|
|
kExprCallIndirect, sig_index, table2])
|
|
.exportAs('call2');
|
|
builder.addFunction('return_call2', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, // function index
|
|
kExprReturnCallIndirect, sig_index, table2])
|
|
.exportAs('return_call2');
|
|
|
|
builder.addFunction('call_invalid_sig', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, kExprGetLocal, 0, // function index + param
|
|
kExprCallIndirect, other_sig, table2])
|
|
.exportAs('call_invalid_sig');
|
|
builder.addFunction('return_call_invalid_sig', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, kExprGetLocal, 0, // function index + param
|
|
kExprReturnCallIndirect, other_sig, table2])
|
|
.exportAs('return_call_invalid_sig');
|
|
|
|
// We want to crash if we call through the table with index 0.
|
|
builder.addElementSegment(placeholder, 0, false,
|
|
[f_unreachable, f_unreachable, f_unreachable], false);
|
|
builder.addElementSegment(table1, 0, false, [f1, f2, f3], false);
|
|
// Keep one slot in table2 uninitialized. We should trap if we call it.
|
|
builder.addElementSegment(table2, 1, false,
|
|
[f_unreachable, f_unreachable, f4, f5], false);
|
|
|
|
const instance = builder.instantiate();
|
|
|
|
assertEquals(v1, instance.exports.call1(0));
|
|
assertEquals(v2, instance.exports.call1(1));
|
|
assertEquals(v3, instance.exports.call1(2));
|
|
assertTraps(kTrapFuncInvalid, () => instance.exports.call1(3));
|
|
assertEquals(v1, instance.exports.return_call1(0));
|
|
assertEquals(v2, instance.exports.return_call1(1));
|
|
assertEquals(v3, instance.exports.return_call1(2));
|
|
assertTraps(kTrapFuncInvalid, () => instance.exports.return_call1(3));
|
|
|
|
// Try to call through the uninitialized table entry.
|
|
assertTraps(kTrapFuncSigMismatch, () => instance.exports.call2(0));
|
|
assertEquals(v4, instance.exports.call2(3));
|
|
assertEquals(v5, instance.exports.call2(4));
|
|
assertTraps(kTrapFuncSigMismatch,
|
|
() => instance.exports.call_invalid_sig(4));
|
|
assertTraps(kTrapFuncSigMismatch, () => instance.exports.return_call2(0));
|
|
assertEquals(v4, instance.exports.return_call2(3));
|
|
assertEquals(v5, instance.exports.return_call2(4));
|
|
assertTraps(kTrapFuncSigMismatch,
|
|
() => instance.exports.return_call_invalid_sig(4));
|
|
})();
|
|
|
|
(function IndirectCallToImportedNonZeroTable() {
|
|
print(arguments.callee.name);
|
|
|
|
const table_size = 10;
|
|
const placeholder = new WebAssembly.Table(
|
|
{ initial: table_size, maximum: table_size, element: "anyfunc" });
|
|
const table = new WebAssembly.Table(
|
|
{ initial: table_size, maximum: table_size, element: "anyfunc" });
|
|
|
|
const builder = new WasmModuleBuilder();
|
|
builder.addImportedTable("m", "placeholder", table_size, table_size);
|
|
const t1 = builder.addImportedTable("m", "table", table_size, table_size);
|
|
|
|
// We initialize the module twice and put the function f1 in the table at
|
|
// the index defined by {g}. Thereby we can initialize the table at different
|
|
// slots for different instances. The function f1 also returns {g} so that we
|
|
// can see that actually different functions get called.
|
|
const g = builder.addImportedGlobal("m", "base", kWasmI32);
|
|
|
|
const sig_index = builder.addType(kSig_i_v);
|
|
const f1 = builder.addFunction("foo", sig_index)
|
|
.addBody([kExprGetGlobal, g, kExprI32Const, 12, kExprI32Add]);
|
|
|
|
builder.addFunction('call', kSig_i_i)
|
|
.addBody([kExprGetLocal, 0, // function index
|
|
kExprCallIndirect, sig_index, t1])
|
|
.exportAs('call');
|
|
|
|
builder.addElementSegment(t1, g, true, [f1.index], true);
|
|
const base1 = 3;
|
|
const base2 = 5;
|
|
|
|
const instance1 = builder.instantiate({
|
|
m: {
|
|
placeholder: placeholder,
|
|
table: table,
|
|
base: base1
|
|
}
|
|
});
|
|
|
|
const instance2 = builder.instantiate({
|
|
m: {
|
|
placeholder: placeholder,
|
|
table: table,
|
|
base: base2
|
|
}
|
|
});
|
|
|
|
assertEquals(base1 + 12, instance1.exports.call(base1));
|
|
assertEquals(base2 + 12, instance1.exports.call(base2));
|
|
assertEquals(base1 + 12, instance2.exports.call(base1));
|
|
assertEquals(base2 + 12, instance2.exports.call(base2));
|
|
})();
|
|
|
|
function js_div(a, b) { return (a / b) | 0; }
|
|
|
|
(function CallImportedFunction() {
|
|
let kTableSize = 10;
|
|
print(arguments.callee.name);
|
|
|
|
var builder = new WasmModuleBuilder();
|
|
|
|
let div = builder.addImport("q", "js_div", kSig_i_ii);
|
|
builder.addImportedTable("q", "placeholder", kTableSize, kTableSize);
|
|
let table_index = builder.addImportedTable("q", "table", kTableSize, kTableSize);
|
|
let g = builder.addImportedGlobal("q", "base", kWasmI32);
|
|
|
|
let sig_index = builder.addType(kSig_i_ii);
|
|
builder.addFunction("placeholder", sig_index)
|
|
.addBody([kExprGetLocal, 0]);
|
|
|
|
builder.addElementSegment(table_index, g, true, [div]);
|
|
builder.addFunction("main", kSig_i_ii)
|
|
.addBody([
|
|
kExprI32Const, 55, // --
|
|
kExprGetLocal, 0, // --
|
|
kExprGetLocal, 1, // --
|
|
kExprCallIndirect, 0, table_index]) // --
|
|
.exportAs("main");
|
|
|
|
let m = new WebAssembly.Module(builder.toBuffer());
|
|
|
|
let table = new WebAssembly.Table({
|
|
element: "anyfunc",
|
|
initial: kTableSize,
|
|
maximum: kTableSize
|
|
});
|
|
let placeholder = new WebAssembly.Table({
|
|
element: "anyfunc",
|
|
initial: kTableSize,
|
|
maximum: kTableSize
|
|
});
|
|
|
|
let instance = new WebAssembly.Instance(m, {
|
|
q: {
|
|
base: 0, table: table, placeholder: placeholder,
|
|
js_div: js_div
|
|
}
|
|
});
|
|
|
|
assertEquals(13, instance.exports.main(4, 0));
|
|
})();
|