fe531e1feb
This CL replaces the equirecursive type system for wasm-gc with the isorecursive hybrid type system presented here: https://github.com/WebAssembly/gc/issues/257. In broad strokes, this includes the following changes: - In the module decoder, remove equirecursive types. Implement recursive type groups, subtype definitions, and function/struct/array definitions. Treat nominal modules as syntactic sugar of an isorecursive module, where all types belong in the same recursive group. - Remove rtt.sub and all related infrastructure. - Change subtyping to work with explicit supertypes only. - Add ValidSubtypeDefinition in subtyping, to check that subtype declarations are valid during decoding. - Remove the subtyping cache. - Add support for functions to have specific signature index in WasmModuleBuilder and in test-gc.cc. - Adapt tests. Current restrictions: - Recursive groups are not stored beyond decoding. - Type canonicalization is not implemented. No tests relying on types being considered identical post-canonicalization. - No cross-module subtyping is possible. Tests relying on cross-module subtyping have been commented out. Bug: v8:7748 Change-Id: I69fd04ecc5611f6230c95d5c89d1c520163fffae Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3416239 Reviewed-by: Tobias Tebbi <tebbi@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#78816}
138 lines
4.1 KiB
JavaScript
138 lines
4.1 KiB
JavaScript
// Copyright 2021 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-gc --no-liftoff --experimental-wasm-nn-locals
|
|
|
|
d8.file.execute("test/mjsunit/wasm/wasm-module-builder.js");
|
|
|
|
// Test that comparisons with array length in a loop get optimized away.
|
|
(function ArrayLoopOptimizationTest() {
|
|
var builder = new WasmModuleBuilder();
|
|
var array_index = builder.addArray(kWasmI32, true);
|
|
|
|
// Increase these parameters to measure performance.
|
|
let array_size = 10; // 100000000;
|
|
let iterations = 1; // 50;
|
|
|
|
builder.addFunction("array_inc", kSig_v_v)
|
|
.addLocals(wasmRefType(array_index), 1)
|
|
.addLocals(kWasmI32, 2)
|
|
// Locals: 0 -> array, 1 -> length, 2 -> index
|
|
.addBody([
|
|
...wasmI32Const(array_size),
|
|
kExprCallFunction, 1,
|
|
kExprLocalSet, 0,
|
|
|
|
// length = array.length
|
|
kExprLocalGet, 0,
|
|
kGCPrefix, kExprArrayLen, array_index,
|
|
kExprLocalSet, 1,
|
|
|
|
// while (true) {
|
|
kExprLoop, kWasmVoid,
|
|
// if (index < length) {
|
|
kExprLocalGet, 2,
|
|
kExprLocalGet, 1,
|
|
kExprI32LtU,
|
|
kExprIf, kWasmVoid,
|
|
// array[index] = array[index] + 5;
|
|
kExprLocalGet, 0,
|
|
kExprLocalGet, 2,
|
|
kExprLocalGet, 0,
|
|
kExprLocalGet, 2,
|
|
kGCPrefix, kExprArrayGet, array_index,
|
|
kExprI32Const, 5,
|
|
kExprI32Add,
|
|
kGCPrefix, kExprArraySet, array_index,
|
|
// index = index + 1;
|
|
kExprLocalGet, 2,
|
|
kExprI32Const, 1,
|
|
kExprI32Add,
|
|
kExprLocalSet, 2,
|
|
// continue;
|
|
kExprBr, 1,
|
|
// }
|
|
// break;
|
|
kExprEnd,
|
|
// }
|
|
kExprEnd])
|
|
.exportFunc();
|
|
|
|
builder.addFunction("make_array",
|
|
makeSig([kWasmI32], [wasmRefType(array_index)]))
|
|
.addBody([kExprLocalGet, 0, kGCPrefix, kExprArrayNewDefault, array_index])
|
|
|
|
var instance = builder.instantiate({});
|
|
|
|
let before = Date.now();
|
|
for (let i = 0; i < iterations; i++) {
|
|
instance.exports.array_inc();
|
|
}
|
|
let after = Date.now();
|
|
print(
|
|
"Average of " + iterations + " runs: " +
|
|
(after - before)/iterations + "ms");
|
|
})();
|
|
|
|
(function ImmutableLoadThroughEffect() {
|
|
var builder = new WasmModuleBuilder();
|
|
builder.setNominal();
|
|
var struct = builder.addStruct([
|
|
makeField(kWasmI32, false), makeField(kWasmI32, true)]);
|
|
|
|
let effect = builder.addImport('m', 'f', kSig_v_v);
|
|
|
|
builder.addFunction("main", kSig_i_i)
|
|
.addLocals(wasmRefType(struct), 1)
|
|
.addBody([
|
|
// Initialize an object
|
|
kExprLocalGet, 0,
|
|
kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add,
|
|
kGCPrefix, kExprStructNew, struct,
|
|
kExprLocalSet, 1,
|
|
// Introduce unknown effect
|
|
kExprCallFunction, effect,
|
|
// TF should be able to eliminate this load...
|
|
kExprLocalGet, 1,
|
|
kGCPrefix, kExprStructGet, struct, 0,
|
|
// ... but not this one.
|
|
kExprLocalGet, 1,
|
|
kGCPrefix, kExprStructGet, struct, 1,
|
|
kExprI32Add
|
|
])
|
|
.exportFunc();
|
|
|
|
var instance = builder.instantiate({m : { f: function () {} }});
|
|
|
|
assertEquals(85, instance.exports.main(42));
|
|
})();
|
|
|
|
(function FunctionTypeCheckThroughEffect() {
|
|
var builder = new WasmModuleBuilder();
|
|
var sig = builder.addType(kSig_i_i);
|
|
|
|
let effect = builder.addImport('m', 'f', kSig_v_v);
|
|
|
|
builder.addFunction("input", sig)
|
|
.addBody([kExprLocalGet, 0])
|
|
.exportFunc();
|
|
|
|
builder.addFunction("main", makeSig([wasmRefType(kWasmFuncRef)], [kWasmI32]))
|
|
.addBody([
|
|
// Type check the function
|
|
kExprLocalGet, 0, kGCPrefix, kExprRttCanon, sig, kGCPrefix, kExprRefCast,
|
|
kExprDrop,
|
|
// Introduce unknown effect
|
|
kExprCallFunction, effect,
|
|
// TF should be able to eliminate the second type check, and return the
|
|
// constant 1.
|
|
kExprLocalGet, 0, kGCPrefix, kExprRttCanon, sig,
|
|
kGCPrefix, kExprRefTest])
|
|
.exportFunc();
|
|
|
|
var instance = builder.instantiate({m : { f: function () {} }});
|
|
|
|
assertEquals(1, instance.exports.main(instance.exports.input));
|
|
})();
|