v8/test/mjsunit/wasm/indirect-call-non-zero-table.js
Manos Koukoutos 7c74a9caea [wasm][test] Represent constant expressions with bytes
Maintaining an AST class just for testing constant exressions does not
seem justified. This CL changes constant expressions in mjsunit tests
to be represented with bytes, like regular expressions.

Change-Id: If5ec5f4d863176952442b1a7e2fec8a61e385971
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3714237
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81266}
2022-06-21 09:03:18 +00:00

205 lines
7.1 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-return-call
d8.file.execute("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([kExprLocalGet, 0, // function index
kExprCallIndirect, sig_index, table1])
.exportAs('call1');
builder.addFunction('return_call1', kSig_i_i)
.addBody([kExprLocalGet, 0, // function index
kExprReturnCallIndirect, sig_index, table1])
.exportAs('return_call1');
builder.addFunction('call2', kSig_i_i)
.addBody([kExprLocalGet, 0, // function index
kExprCallIndirect, sig_index, table2])
.exportAs('call2');
builder.addFunction('return_call2', kSig_i_i)
.addBody([kExprLocalGet, 0, // function index
kExprReturnCallIndirect, sig_index, table2])
.exportAs('return_call2');
builder.addFunction('call_invalid_sig', kSig_i_i)
.addBody([kExprLocalGet, 0, kExprLocalGet, 0, // function index + param
kExprCallIndirect, other_sig, table2])
.exportAs('call_invalid_sig');
builder.addFunction('return_call_invalid_sig', kSig_i_i)
.addBody([kExprLocalGet, 0, kExprLocalGet, 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.addActiveElementSegment(placeholder, wasmI32Const(0),
[f_unreachable, f_unreachable, f_unreachable]);
builder.addActiveElementSegment(table1, wasmI32Const(0),
[f1, f2, f3]);
// Keep one slot in table2 uninitialized. We should trap if we call it.
builder.addActiveElementSegment(table2, wasmI32Const(1),
[f_unreachable, f_unreachable, f4, f5]);
const instance = builder.instantiate();
assertEquals(v1, instance.exports.call1(0));
assertEquals(v2, instance.exports.call1(1));
assertEquals(v3, instance.exports.call1(2));
assertTraps(kTrapTableOutOfBounds, () => 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(kTrapTableOutOfBounds, () => 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([kExprGlobalGet, g, kExprI32Const, 12, kExprI32Add]);
builder.addFunction('call', kSig_i_i)
.addBody([kExprLocalGet, 0, // function index
kExprCallIndirect, sig_index, t1])
.exportAs('call');
builder.addActiveElementSegment(t1, [kExprGlobalGet, g], [f1.index]);
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([kExprLocalGet, 0]);
builder.addActiveElementSegment(table_index, [kExprGlobalGet, g], [div]);
builder.addFunction("main", kSig_i_ii)
.addBody([
kExprI32Const, 55, // --
kExprLocalGet, 0, // --
kExprLocalGet, 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));
})();