v8/test/mjsunit/wasm/reference-tables.js

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

543 lines
19 KiB
JavaScript
Raw Normal View History

// Copyright 2020 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
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
(function TestTables() {
[wasm] Internal representation for function references Design doc: bit.ly/3jEVgzz We separate the internal representation of function references in Wasm from their JSFunction-based (external) representation. This improves performance of call_ref by requiring less indirections to load the context and call target from a function reference. In the boundary between wasm and JS/the C API, we add transformations between the two representations. Detailed changes: - Introduce WasmInternalFunction, containing fields required by call_ref, as well as a reference to the corresponding WasmExternalFunction. Add a reference to the WasmInternalFunction in WasmFunctionData. The {WasmInternalFunction::FromExternal} helper extracts the internal out of an external function. - Change {WasmInstanceObject::external_functions()} to internal functions. - Change wasm function tables to contain internal functions. - Change the following code to use internal functions: - call_ref in liftoff and Turbofan - function type checks in liftoff and Turbofan - CallRefIC and GenericJSToWasmWrapper builtins - {InitExprInterface::RefFunc} - module-compiler.cc in {ProcessTypeFeedback} - In module-instantiate.cc, in function-rtt creation. - Add transformations between internal and external functions in: - WasmWrapperGraphBuilder::{ToJS, BuildUnpackObjectWrapper, FromJS, BuildJSToJSWrapper}. - debug-wasm-objects.cc in {FunctionProxy::Get}, {WasmValueObject::New} and {AddWasmTableObjectInternalProperties}. - runtime-wasm.cc in ReplaceWrapper - the C and JS APIs - module-instantiate.cc, in import and export processing, as well as {InitializeIndirectFunctionTables} - WasmTableObject::{IsValidElement, SetFunctionTableEntry} - {WasmGlobalObject::SetFuncRef} - Simplify body descriptors of WasmExternalFunction variants. - Adjust tests. Bug: v8:11510 Change-Id: I8377f46f55c3771391ae1c5c8201a83854ee7878 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3277878 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#78068}
2021-11-23 14:31:18 +00:00
print(arguments.callee.name);
var exporting_instance = (function() {
var builder = new WasmModuleBuilder();
var binary_type = builder.addType(kSig_i_ii);
builder.addFunction('addition', kSig_i_ii)
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add])
.exportFunc();
builder.addFunction('succ', kSig_i_i)
.addBody([kExprLocalGet, 0, kExprI32Const, 1, kExprI32Add])
.exportFunc();
builder.addTable(wasmRefNullType(binary_type), 1, 100).exportAs('table');
return builder.instantiate({});
})();
// Wrong type for imported table.
assertThrows(() => {
var builder = new WasmModuleBuilder();
var unary_type = builder.addType(kSig_i_i);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefNullType(unary_type));
builder.instantiate({imports: {table: exporting_instance.exports.table}})
}, WebAssembly.LinkError, /imported table does not match the expected type/);
// Type for imported table must match exactly.
assertThrows(() => {
var builder = new WasmModuleBuilder();
builder.addImportedTable('imports', 'table', 1, 100, kWasmFuncRef);
builder.instantiate({imports: {table: exporting_instance.exports.table}})
}, WebAssembly.LinkError, /imported table does not match the expected type/);
var instance = (function() {
var builder = new WasmModuleBuilder();
var unary_type = builder.addType(kSig_i_i);
var binary_type = builder.addType(kSig_i_ii);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefNullType(binary_type));
var table =
builder.addTable(wasmRefNullType(unary_type), 10).exportAs('table');
builder.addTable(kWasmFuncRef, 1).exportAs('generic_table');
builder
.addFunction(
'table_test', makeSig([wasmRefType(unary_type)], [kWasmI32]))
// Set table[0] to input function, then retrieve it and call it.
.addBody([
kExprI32Const, 0, kExprLocalGet, 0, kExprTableSet, table.index,
kExprI32Const, 42, kExprI32Const, 0, kExprTableGet, table.index,
kExprCallRef, unary_type,
])
.exportFunc();
// Same, but with table[1] and call_indirect
builder
.addFunction(
'table_indirect_test',
makeSig([wasmRefType(unary_type)], [kWasmI32]))
.addBody([
kExprI32Const, 1, kExprLocalGet, 0, kExprTableSet, table.index,
kExprI32Const, 42, kExprI32Const, 0, kExprCallIndirect, unary_type,
table.index
])
.exportFunc();
// Instantiate with a table of the correct type.
return builder.instantiate(
{imports: {table: exporting_instance.exports.table}});
})();
// This module is valid.
assertTrue(!!instance);
// The correct function reference is preserved when setting it to and getting
// it back from a table.
assertEquals(
43, instance.exports.table_test(exporting_instance.exports.succ));
// Same for call indirect (the indirect call tables are also set correctly).
assertEquals(
43,
instance.exports.table_indirect_test(exporting_instance.exports.succ));
// Setting from JS API respects types.
instance.exports.generic_table.set(0, exporting_instance.exports.succ);
instance.exports.table.set(0, exporting_instance.exports.succ);
assertThrows(
() => instance.exports.table.set(0, exporting_instance.exports.addition),
TypeError,
/Argument 1 is invalid for table: assigned exported function has to be a subtype of the expected type/);
})();
(function TestNonNullableTables() {
[wasm] Internal representation for function references Design doc: bit.ly/3jEVgzz We separate the internal representation of function references in Wasm from their JSFunction-based (external) representation. This improves performance of call_ref by requiring less indirections to load the context and call target from a function reference. In the boundary between wasm and JS/the C API, we add transformations between the two representations. Detailed changes: - Introduce WasmInternalFunction, containing fields required by call_ref, as well as a reference to the corresponding WasmExternalFunction. Add a reference to the WasmInternalFunction in WasmFunctionData. The {WasmInternalFunction::FromExternal} helper extracts the internal out of an external function. - Change {WasmInstanceObject::external_functions()} to internal functions. - Change wasm function tables to contain internal functions. - Change the following code to use internal functions: - call_ref in liftoff and Turbofan - function type checks in liftoff and Turbofan - CallRefIC and GenericJSToWasmWrapper builtins - {InitExprInterface::RefFunc} - module-compiler.cc in {ProcessTypeFeedback} - In module-instantiate.cc, in function-rtt creation. - Add transformations between internal and external functions in: - WasmWrapperGraphBuilder::{ToJS, BuildUnpackObjectWrapper, FromJS, BuildJSToJSWrapper}. - debug-wasm-objects.cc in {FunctionProxy::Get}, {WasmValueObject::New} and {AddWasmTableObjectInternalProperties}. - runtime-wasm.cc in ReplaceWrapper - the C and JS APIs - module-instantiate.cc, in import and export processing, as well as {InitializeIndirectFunctionTables} - WasmTableObject::{IsValidElement, SetFunctionTableEntry} - {WasmGlobalObject::SetFuncRef} - Simplify body descriptors of WasmExternalFunction variants. - Adjust tests. Bug: v8:11510 Change-Id: I8377f46f55c3771391ae1c5c8201a83854ee7878 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3277878 Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Jakob Gruber <jgruber@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Manos Koukoutos <manoskouk@chromium.org> Cr-Commit-Position: refs/heads/main@{#78068}
2021-11-23 14:31:18 +00:00
print(arguments.callee.name);
var builder = new WasmModuleBuilder();
var binary_type = builder.addType(kSig_i_ii);
[wasm-gc] Implement iso-recursive types 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}
2022-01-27 16:24:31 +00:00
var addition = builder.addFunction('addition', binary_type).addBody([
kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Add
]);
var subtraction =
[wasm-gc] Implement iso-recursive types 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}
2022-01-27 16:24:31 +00:00
builder.addFunction('subtraction', binary_type)
.addBody([kExprLocalGet, 0, kExprLocalGet, 1, kExprI32Sub])
.exportFunc();
var table = builder.addTable(wasmRefType(binary_type), 3, 3,
[kExprRefFunc, addition.index]);
builder.addFunction('init', kSig_v_v)
.addBody([
kExprI32Const, 1, kExprRefFunc, subtraction.index, kExprTableSet,
table.index
])
.exportFunc();
// (index, arg1, arg2) -> table[index](arg1, arg2)
builder.addFunction('table_test', kSig_i_iii)
.addBody([
kExprLocalGet, 1, kExprLocalGet, 2, kExprLocalGet, 0, kExprCallIndirect,
binary_type, table.index
])
.exportFunc();
var instance = builder.instantiate({});
assertTrue(!!instance);
instance.exports.init();
assertEquals(44, instance.exports.table_test(0, 33, 11));
assertEquals(22, instance.exports.table_test(1, 33, 11));
})();
(function TestAnyRefTable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array_type = builder.addArray(kWasmI32);
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let table = builder.addTable(kWasmAnyRef, 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(111), ...wasmI32Const(222),
kGCPrefix, kExprArrayNewFixed, array_type, 2],
[...wasmI32Const(-31), kGCPrefix, kExprI31New],
[...wasmI32Const(10), kGCPrefix, kExprStructNew, struct_type],
[kExprRefNull, kEqRefCode]],
kWasmAnyRef);
// return ...static_cast<array_type>(table[0])
builder.addFunction("array_getter", kSig_ii_v)
.addLocals(wasmRefNullType(array_type), 1)
.addBody([
kExprI32Const, 0, kExprTableGet, 0,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type,
kExprLocalSet, 0,
kExprLocalGet, 0,
...wasmI32Const(0), kGCPrefix, kExprArrayGet, array_type,
kExprLocalGet, 0,
...wasmI32Const(1), kGCPrefix, kExprArrayGet, array_type])
.exportFunc();
// return static_cast<i31>(table[1])
builder.addFunction("i31_getter", kSig_i_v)
.addBody([
kExprI32Const, 1, kExprTableGet, 0,
kGCPrefix, kExprRefAsI31,
kGCPrefix, kExprI31GetS])
.exportFunc();
// return static_cast<struct_type>(table[2]).field_0
builder.addFunction("struct_getter", kSig_i_v)
.addBody([
kExprI32Const, 2, kExprTableGet, 0,
Reland "Reland "[wasm-gc] Ref types: Convert dataref to structref"" This is a reland of commit 3b883e787df53fc8ec829ead16a2ed4ff268ce2e Fixed a test case that was merged in the meantime still using the old kExprRefAsData which is now called kExprRefAsStruct. Original change's description: > Reland "[wasm-gc] Ref types: Convert dataref to structref" > > This is a reland of commit 20327d1599425947e264029461bc0ea03751a4a7 > > Changed in reland: > - Added new flag wasm-gc-structref-as-dataref which defaults to true > and preserves the existing behavior. > - Passing --no-wasm-gc-structref-as-dataref enables the new behavior. > - The flag affects static subtyping information between structref and > arrays and the corresponding cast, test and br_on instructions. > - Even with the old behavior the name still changed to "structref". > > Original change's description: > > [wasm-gc] Ref types: Convert dataref to structref > > > > This change changes the type hierarchy in a non-backwards compatible > > way: dataref is replaced with structref meaning that arrayref is > > no longer a subtype of it. > > > > Bug: v8:7748 > > Change-Id: I965267d9ed11ea7c7d7df133cc39ee63e6b5abc3 > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3929041 > > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> > > Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#83515} > > Bug: v8:7748 > Change-Id: I2d8dd49dbc56246c087ac93452a87f860ead2195 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3945109 > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> > Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> > Cr-Commit-Position: refs/heads/main@{#83697} Bug: v8:7748 Change-Id: I54f7b141ffc5b7597420fa0c838412be825a260b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3952936 Auto-Submit: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#83706}
2022-10-14 08:46:34 +00:00
kGCPrefix, kExprRefAsStruct, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();
// return table[3] == null
builder.addFunction("null_getter", kSig_i_v)
.addBody([kExprI32Const, 3, kExprTableGet, 0, kExprRefIsNull])
.exportFunc();
let instance = builder.instantiate({});
assertTrue(!!instance);
assertEquals([111, 222], instance.exports.array_getter());
assertEquals(-31, instance.exports.i31_getter());
assertEquals(10, instance.exports.struct_getter());
assertEquals(1, instance.exports.null_getter());
})();
(function TestAnyRefTableNotNull() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array_type = builder.addArray(kWasmI32);
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let table = builder.addTable(wasmRefType(kWasmAnyRef), 3, 6,
[...wasmI32Const(111), ...wasmI32Const(222),
kGCPrefix, kExprArrayNewFixed, array_type, 2])
.exportAs("table");
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(111), ...wasmI32Const(222),
kGCPrefix, kExprArrayNewFixed, array_type, 2],
[...wasmI32Const(-31), kGCPrefix, kExprI31New],
[...wasmI32Const(10), kGCPrefix, kExprStructNew, struct_type]],
wasmRefType(kWasmAnyRef));
// return ...cast<array_type>(table.get(0))
builder.addFunction("array_getter", kSig_ii_v)
.addLocals(wasmRefNullType(array_type), 1)
.addBody([
kExprI32Const, 0, kExprTableGet, 0,
kGCPrefix, kExprRefAsArray,
kGCPrefix, kExprRefCast, array_type,
kExprLocalSet, 0,
kExprLocalGet, 0,
...wasmI32Const(0), kGCPrefix, kExprArrayGet, array_type,
kExprLocalGet, 0,
...wasmI32Const(1), kGCPrefix, kExprArrayGet, array_type])
.exportFunc();
// return cast<i31>(table.get(1))
builder.addFunction("i31_getter", kSig_i_v)
.addBody([
kExprI32Const, 1, kExprTableGet, 0,
kGCPrefix, kExprRefAsI31,
kGCPrefix, kExprI31GetS])
.exportFunc();
// return cast<struct_type>(table.get(param<0>))[0]
builder.addFunction("struct_getter", kSig_i_i)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
Reland "Reland "[wasm-gc] Ref types: Convert dataref to structref"" This is a reland of commit 3b883e787df53fc8ec829ead16a2ed4ff268ce2e Fixed a test case that was merged in the meantime still using the old kExprRefAsData which is now called kExprRefAsStruct. Original change's description: > Reland "[wasm-gc] Ref types: Convert dataref to structref" > > This is a reland of commit 20327d1599425947e264029461bc0ea03751a4a7 > > Changed in reland: > - Added new flag wasm-gc-structref-as-dataref which defaults to true > and preserves the existing behavior. > - Passing --no-wasm-gc-structref-as-dataref enables the new behavior. > - The flag affects static subtyping information between structref and > arrays and the corresponding cast, test and br_on instructions. > - Even with the old behavior the name still changed to "structref". > > Original change's description: > > [wasm-gc] Ref types: Convert dataref to structref > > > > This change changes the type hierarchy in a non-backwards compatible > > way: dataref is replaced with structref meaning that arrayref is > > no longer a subtype of it. > > > > Bug: v8:7748 > > Change-Id: I965267d9ed11ea7c7d7df133cc39ee63e6b5abc3 > > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3929041 > > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> > > Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> > > Cr-Commit-Position: refs/heads/main@{#83515} > > Bug: v8:7748 > Change-Id: I2d8dd49dbc56246c087ac93452a87f860ead2195 > Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3945109 > Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> > Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> > Cr-Commit-Position: refs/heads/main@{#83697} Bug: v8:7748 Change-Id: I54f7b141ffc5b7597420fa0c838412be825a260b Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3952936 Auto-Submit: Matthias Liedtke <mliedtke@chromium.org> Reviewed-by: Jakob Kummerow <jkummerow@chromium.org> Commit-Queue: Matthias Liedtke <mliedtke@chromium.org> Commit-Queue: Jakob Kummerow <jkummerow@chromium.org> Cr-Commit-Position: refs/heads/main@{#83706}
2022-10-14 08:46:34 +00:00
kGCPrefix, kExprRefAsStruct, kGCPrefix, kExprRefCast, struct_type,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();
builder.addFunction("grow_table", kSig_v_v)
.addBody([
...wasmI32Const(20), kGCPrefix, kExprStructNew, struct_type,
kExprI32Const, 1,
kNumericPrefix, kExprTableGrow, 0,
kExprDrop,
])
.exportFunc();
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStructNew, struct_type,
kGCPrefix, kExprExternExternalize,
])
.exportFunc();
let instance = builder.instantiate({});
let wasmTable = instance.exports.table;
assertEquals([111, 222], instance.exports.array_getter());
assertEquals(-31, instance.exports.i31_getter());
assertEquals(10, instance.exports.struct_getter(2));
assertTraps(kTrapTableOutOfBounds, () => instance.exports.struct_getter(3));
instance.exports.grow_table();
assertEquals(20, instance.exports.struct_getter(3));
assertThrows(() => wasmTable.grow(1), TypeError,
/Argument 1 must be specified for non-nullable element type/);
wasmTable.grow(1, instance.exports.create_struct(33));
assertEquals(33, instance.exports.struct_getter(4));
// undefined is ok for (ref any), but not null.
wasmTable.set(4, undefined);
assertThrows(() => wasmTable.set(4, null), TypeError,
/Argument 1 is invalid/);
})();
(function TestStructRefTable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let table = builder.addTable(wasmRefNullType(struct_type), 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(10), kGCPrefix, kExprStructNew, struct_type],
[...wasmI32Const(11), kGCPrefix, kExprStructNew, struct_type],
[kExprRefNull, struct_type]],
wasmRefNullType(struct_type));
builder.addFunction("struct_getter", kSig_i_i)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();
builder.addFunction("null_getter", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprTableGet, 0, kExprRefIsNull])
.exportFunc();
let instance = builder.instantiate({});
assertTrue(!!instance);
assertEquals(10, instance.exports.struct_getter(0));
assertEquals(11, instance.exports.struct_getter(1));
assertEquals(1, instance.exports.null_getter(2));
})();
(function TestArrayRefTable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let array_type = builder.addArray(kWasmI32);
let table = builder.addTable(wasmRefNullType(array_type), 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(10), ...wasmI32Const(11), ...wasmI32Const(12),
kGCPrefix, kExprArrayNewFixed, array_type, 3],
[kGCPrefix, kExprArrayNewFixed, array_type, 0],
[kExprRefNull, array_type]],
wasmRefNullType(array_type));
builder.addFunction("array_getter", kSig_i_ii)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kExprLocalGet, 1,
kGCPrefix, kExprArrayGet, array_type])
.exportFunc();
builder.addFunction("null_getter", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprTableGet, 0, kExprRefIsNull])
.exportFunc();
let instance = builder.instantiate({});
assertTrue(!!instance);
assertEquals(10, instance.exports.array_getter(0, 0));
assertEquals(11, instance.exports.array_getter(0, 1));
assertEquals(12, instance.exports.array_getter(0, 2));
assertEquals(0, instance.exports.null_getter(1));
assertTraps(kTrapArrayOutOfBounds,
() => instance.exports.array_getter(1, 0));
assertEquals(1, instance.exports.null_getter(2));
})();
(function TestRefTableInvalidSegmentType() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct_type_a = builder.addStruct([makeField(kWasmI32, false)]);
let struct_type_b = builder.addStruct([makeField(kWasmI64, false)]);
let table = builder.addTable(wasmRefNullType(struct_type_a), 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(10), kGCPrefix, kExprStructNew, struct_type_b]],
wasmRefNullType(struct_type_b)); // Mismatches table type.
assertThrows(() => builder.instantiate({}),
WebAssembly.CompileError,
/Element segment .* is not a subtype of referenced table/);
})();
(function TestRefTableInvalidSegmentExpressionType() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct_type_a = builder.addStruct([makeField(kWasmI32, false)]);
let struct_type_b = builder.addStruct([makeField(kWasmI64, false)]);
let table = builder.addTable(wasmRefNullType(struct_type_a), 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI64Const(10), kGCPrefix, kExprStructNew, struct_type_b]],
wasmRefNullType(struct_type_a));
assertThrows(() => builder.instantiate({}),
WebAssembly.CompileError,
/expected \(ref null 0\), got \(ref 1\)/);
})();
(function TestMultiModuleRefTableEquivalentTypes() {
print(arguments.callee.name);
let exporting_instance = (() => {
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
builder.addTable(wasmRefNullType(struct_type), 1, 100).exportAs('table');
return builder.instantiate({});
})();
// Mismatching struct definition.
assertThrows(() => {
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI64, false)]);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefNullType(struct_type));
builder.instantiate({imports: {table: exporting_instance.exports.table}})
}, WebAssembly.LinkError, /imported table does not match the expected type/);
// Mismatching nullability.
assertThrows(() => {
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefType(struct_type));
builder.instantiate({imports: {table: exporting_instance.exports.table}})
}, WebAssembly.LinkError, /imported table does not match the expected type/);
// Equivalent struct type.
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let struct_type_invalid = builder.addStruct([makeField(kWasmI64, false)]);
let struct_type_sub = builder.addStruct(
[makeField(kWasmI32, false), makeField(kWasmI32, false)], struct_type);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefNullType(struct_type));
builder.addFunction("invalid_struct", makeSig([], [kWasmExternRef]))
.addBody([
kExprI64Const, 44,
kGCPrefix, kExprStructNew, struct_type_invalid,
kGCPrefix, kExprExternExternalize])
.exportFunc();
builder.addFunction("valid_struct", makeSig([], [kWasmExternRef]))
.addBody([
kExprI32Const, 44,
kGCPrefix, kExprStructNew, struct_type,
kGCPrefix, kExprExternExternalize])
.exportFunc();
builder.addFunction("valid_struct_sub", makeSig([], [kWasmExternRef]))
.addBody([
kExprI32Const, 55,
kExprI32Const, 66,
kGCPrefix, kExprStructNew, struct_type_sub,
kGCPrefix, kExprExternExternalize])
.exportFunc();
let table = exporting_instance.exports.table;
let instance = builder.instantiate({imports: {table}});
table.grow(5, undefined);
assertThrows(() => table.set(1, instance.exports.invalid_struct()),
TypeError);
table.set(1, instance.exports.valid_struct());
table.set(2, instance.exports.valid_struct_sub());
table.set(3, null);
assertThrows(() => table.set(1, undefined),
TypeError);
})();
(function TestMultiModuleRefTableSuperType() {
print(arguments.callee.name);
let exporting_instance = (() => {
let builder = new WasmModuleBuilder();
let struct_type_base = builder.addStruct([makeField(kWasmI32, false)]);
let struct_type =
builder.addStruct([makeField(kWasmI32, false)], struct_type_base);
builder.addTable(wasmRefNullType(struct_type), 1, 100).exportAs('table');
return builder.instantiate({});
})();
let builder = new WasmModuleBuilder();
let struct_type_base = builder.addStruct([makeField(kWasmI32, false)]);
let struct_type =
builder.addStruct([makeField(kWasmI32, false)], struct_type_base);
builder.addImportedTable(
'imports', 'table', 1, 100, wasmRefNullType(struct_type));
builder.addFunction("struct_base", makeSig([], [kWasmExternRef]))
.addBody([
kExprI32Const, 66,
kGCPrefix, kExprStructNew, struct_type_base,
kGCPrefix, kExprExternExternalize])
.exportFunc();
let table = exporting_instance.exports.table;
let instance = builder.instantiate({imports: {table}});
assertThrows(() => table.set(0, instance.exports.struct_base()), TypeError);
assertThrows(() => table.grow(1, instance.exports.struct_base()), TypeError);
})();
(function TestRefTableNotNull() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let table = builder.addTable(wasmRefType(struct_type), 2, 6,
[...wasmI32Const(111),
kGCPrefix, kExprStructNew, struct_type])
.exportAs("table");
builder.addFunction("create_struct", makeSig([kWasmI32], [kWasmExternRef]))
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprStructNew, struct_type,
kGCPrefix, kExprExternExternalize,
])
.exportFunc();
builder.addFunction("struct_getter", kSig_i_i)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprStructGet, struct_type, 0])
.exportFunc();
let instance = builder.instantiate({});
let wasmTable = instance.exports.table;
// Initial values.
assertEquals(111, instance.exports.struct_getter(0));
assertEquals(111, instance.exports.struct_getter(1));
assertTraps(kTrapTableOutOfBounds, () => instance.exports.struct_getter(2));
assertThrows(() => wasmTable.grow(1), TypeError,
/Argument 1 must be specified for non-nullable element type/);
wasmTable.grow(1, instance.exports.create_struct(222));
assertEquals(222, instance.exports.struct_getter(2));
assertThrows(() => wasmTable.set(2, undefined), TypeError,
/Argument 1 is invalid/);
assertThrows(() => wasmTable.set(2, null), TypeError,
/Argument 1 is invalid/);
wasmTable.set(2, instance.exports.create_struct(333));
assertEquals(333, instance.exports.struct_getter(2));
})();