v8/test/mjsunit/wasm/call_indirect.js
Manos Koukoutos 4f0ef8c31d [wasm] Use isorecursive canonical types for call_indirect
Currently, we canonicalize types for call_indirect by looking in the
current module for a signature of the same shape. This is not enough
as of wasm-gc. Instead, the canonical identifier representing a type
has to be computed via isorecursive canonicalization.
This change is implemented behind a flag for now.
Future work: Also integrate export wrappers with isorecursive
canonical types. We need to store wrappers in instance-independent
storage.

Drive-by:
- Always emit type check for call_indirect. We did not emit a check
  only when typed-function-references was enabled, but not gc. This
  is not something that will be possible long-term.
- Fix some wasm cctests.

Bug: v8:7748
Change-Id: I7cced187009ac148c833dff5e720a8bb9a717e68
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3784600
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82064}
2022-07-29 08:55:49 +00:00

141 lines
4.8 KiB
JavaScript

// Copyright 2022 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: --experimental-wasm-return-call --experimental-wasm-gc
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
(function TestCallIndirectJSFunction() {
print(arguments.callee.name);
let js_function = function(a, b, c) { return c ? a : b; };
let test = function(is_tail_call) {
const builder = new WasmModuleBuilder();
builder.addType(kSig_i_i);
let sig = builder.addType(kSig_i_iii);
let callee = builder.addImport("m", "f", kSig_i_iii);
let table = builder.addTable(kWasmFuncRef, 10, 10);
builder.addActiveElementSegment(table, wasmI32Const(0), [callee]);
let left = -2;
let right = 3;
builder.addFunction("main", kSig_i_i)
.addBody([...wasmI32Const(left), ...wasmI32Const(right), kExprLocalGet, 0,
...wasmI32Const(0),
is_tail_call ? kExprReturnCallIndirect : kExprCallIndirect,
sig, table.index])
.exportFunc();
let instance = builder.instantiate({m: {f: js_function}});
assertEquals(left, instance.exports.main(1));
assertEquals(right, instance.exports.main(0));
}
test(true);
test(false);
})();
(function TestCallIndirectIsorecursiveTypeCanonicalization() {
print(arguments.callee.name);
let exporting_instance = (function() {
const builder = new WasmModuleBuilder();
builder.setSingletonRecGroups();
let struct_mistyped = builder.addStruct([]);
let struct = builder.addStruct([makeField(kWasmI32, true)]);
let sig_mistyped = builder.addType(
makeSig([wasmRefNullType(struct_mistyped)], [kWasmI32]));
let sig = builder.addType(makeSig([wasmRefNullType(struct)], [kWasmI32]));
builder.addFunction("export", sig)
.addBody([kExprLocalGet, 0, kGCPrefix, kExprStructGet, struct, 0,
...wasmI32Const(0), kExprI32GeS])
.exportFunc();
builder.addFunction("export_mistyped", sig_mistyped)
.addBody([...wasmI32Const(0)])
.exportFunc();
return builder.instantiate();
})();
const builder = new WasmModuleBuilder();
builder.setSingletonRecGroups();
// Have these in the reverse order than before.
let struct = builder.addStruct([makeField(kWasmI32, true)]);
let struct_mistyped = builder.addStruct([]);
let sig = builder.addType(makeSig([wasmRefNullType(struct)], [kWasmI32]));
let sig_identical = builder.addType(
makeSig([wasmRefNullType(struct)], [kWasmI32]));
let sig_mistyped = builder.addType(
makeSig([wasmRefNullType(struct_mistyped)], [kWasmI32]));
let imported = builder.addImport("m", "imp", sig);
let imported_mistyped = builder.addImport("m", "imp_m", sig_mistyped);
let local1 = builder.addFunction("local1", sig)
.addBody([kExprLocalGet, 0, kGCPrefix, kExprStructGet, struct, 0,
...wasmI32Const(0), kExprI32LtS])
.index;
let local2 = builder.addFunction("local2", sig_identical)
.addBody([kExprLocalGet, 0, kGCPrefix, kExprStructGet, struct, 0,
...wasmI32Const(0), kExprI32Eq])
.index;
let mistyped = builder.addFunction("mistyped", kSig_i_i)
.addBody([kExprLocalGet, 0])
.index;
let table_size = 10;
let table = builder.addTable(kWasmFuncRef, table_size, table_size);
builder.addActiveElementSegment(
table.index, wasmI32Const(0),
[[kExprRefFunc, imported], [kExprRefFunc, imported_mistyped],
[kExprRefFunc, local1], [kExprRefFunc, local2], [kExprRefFunc, mistyped]],
table.type);
// Params: Struct field, table index
builder.addFunction("main", kSig_i_ii)
.addBody([kExprLocalGet, 0, kGCPrefix, kExprStructNew, struct,
kExprLocalGet, 1, kExprCallIndirect, sig, table.index])
.exportFunc();
let importing_instance =
builder.instantiate(
{m: {imp: exporting_instance.exports.export,
imp_m: exporting_instance.exports.export_mistyped}});
assertEquals(1, importing_instance.exports.main(10, imported))
assertEquals(0, importing_instance.exports.main(-5, imported))
assertEquals(0, importing_instance.exports.main(10, local1))
assertEquals(1, importing_instance.exports.main(-5, local1))
assertEquals(0, importing_instance.exports.main(10, local2))
assertEquals(1, importing_instance.exports.main(0, local2))
// Mistyped entries
assertTraps(kTrapFuncSigMismatch,
() => importing_instance.exports.main(10, mistyped));
assertTraps(kTrapFuncSigMismatch,
() => importing_instance.exports.main(10, imported_mistyped));
// Null entry
assertTraps(kTrapFuncSigMismatch,
() => importing_instance.exports.main(10, table_size - 1));
assertTraps(kTrapTableOutOfBounds,
() => importing_instance.exports.main(10, table_size));
})();