[wasm.gc] WebAssembly.Table: Allow 'i31ref' type specifier

Bug: v8:7748
Change-Id: Iec34e16219a76e83cfadf7724fda5a6cfa80f69c
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4115748
Reviewed-by: Manos Koukoutos <manoskouk@chromium.org>
Auto-Submit: Matthias Liedtke <mliedtke@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84987}
This commit is contained in:
Matthias Liedtke 2022-12-21 15:59:33 +01:00 committed by V8 LUCI CQ
parent ac65192ce2
commit 2c36e2213f
5 changed files with 85 additions and 15 deletions

View File

@ -1179,8 +1179,10 @@ void WebAssemblyTable(const v8::FunctionCallbackInfo<v8::Value>& args) {
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "arrayref"))) {
type = i::wasm::kWasmArrayRef;
} else if (enabled_features.has_gc() &&
string->StringEquals(v8_str(isolate, "i31ref"))) {
type = i::wasm::kWasmI31Ref;
} else {
// TODO(7748): Add "i31ref".
thrower.TypeError(
"Descriptor property 'element' must be a WebAssembly reference type");
return;

View File

@ -8,31 +8,32 @@ Module instantiated.
Tables populated.
Setting breakpoint
{
columnNumber : 264
columnNumber : 316
lineNumber : 0
scriptId : <scriptId>
}
Paused:
Script wasm://wasm/19fa3802 byte offset 264: Wasm opcode 0x01 (kExprNop)
Script wasm://wasm/2633f626 byte offset 316: Wasm opcode 0x01 (kExprNop)
Scope:
at $main (0:264):
at $main (0:316):
- scope (wasm-expression-stack):
stack:
stack:
- scope (local):
$anyref_local: Struct ((ref $type0))
$anyref_local2: Array ((ref $type1))
$anyref_local_i31: 30 (anyref)
$anyref_local_null: null (anyref)
- scope (module):
instance: exports: "exported_ref_table" (Table), "exported_func_table" (Table), "fill_tables" (Function), "main" (Function)
instance: exports: "exported_ref_table" (Table), "exported_func_table" (Table), "exported_i31_table" (Table), "fill_tables" (Function), "main" (Function)
module: Module
functions: "$my_func": (Function), "$fill_tables": (Function), "$main": (Function)
globals: "$global0": function $my_func() { [native code] } (funcref)
tables:
$import.any_table: 0: Array(2) (anyref), 1: Struct ((ref $type0)), 2: null (anyref)
tables:
$import.any_table: 0: Array(2) (anyref), 1: 321 (anyref), 2: null (anyref), 3: null (anyref)
$import.func_table: 0: function () { [native code] } (funcref), 1: function $my_func() { [native code] } (funcref), 2: null (funcref)
$exported_ref_table: 0: Struct ((ref $type0)), 1: Array ((ref $type1)), 2: 30 (anyref), 3: null (anyref)
$exported_func_table: 0: function external_fct() { [native code] } (funcref), 1: function $my_func() { [native code] } (funcref), 2: null (funcref)
$exported_i31_table: 0: 123456 (i31ref), 1: -123 (i31ref), 2: null (i31ref)
at (anonymous) (0:17):
- scope (global):
-- skipped globals

View File

@ -70,13 +70,15 @@ async function instantiateWasm() {
let struct_type = builder.addStruct([makeField(kWasmI32, false)]);
let array_type = builder.addArray(kWasmI32);
let imported_ref_table =
builder.addImportedTable('import', 'any_table', 3, 3, kWasmAnyRef);
builder.addImportedTable('import', 'any_table', 4, 4, kWasmAnyRef);
let imported_func_table =
builder.addImportedTable('import', 'func_table', 3, 3, kWasmFuncRef);
let ref_table = builder.addTable(kWasmAnyRef, 4)
.exportAs('exported_ref_table');
let func_table = builder.addTable(kWasmFuncRef, 3)
.exportAs('exported_func_table');
let i31ref_table = builder.addTable(kWasmI31Ref, 3)
.exportAs('exported_i31_table');
let func = builder.addFunction('my_func', kSig_v_v).addBody([kExprNop]);
// Make the function "declared".
@ -97,6 +99,10 @@ async function instantiateWasm() {
...wasmI32Const(123), kGCPrefix, kExprStructNew, struct_type,
kExprTableSet, imported_ref_table,
...wasmI32Const(1),
...wasmI32Const(321), kGCPrefix, kExprI31New,
kExprTableSet, imported_ref_table,
// Fill imported func table.
...wasmI32Const(1),
kExprRefFunc, func.index,
@ -106,6 +112,15 @@ async function instantiateWasm() {
...wasmI32Const(1),
kExprRefFunc, func.index,
kExprTableSet, func_table.index,
// Fill i31 table.
...wasmI32Const(0),
...wasmI32Const(123456), kGCPrefix, kExprI31New,
kExprTableSet, i31ref_table.index,
...wasmI32Const(1),
...wasmI32Const(-123), kGCPrefix, kExprI31New,
kExprTableSet, i31ref_table.index,
]).exportFunc();
let body = [
@ -137,7 +152,7 @@ async function instantiateWasm() {
let imports = `{'import' : {
'any_table': (() => {
let js_table =
new WebAssembly.Table({element: 'anyref', initial: 3, maximum: 3});
new WebAssembly.Table({element: 'anyref', initial: 4, maximum: 4});
js_table.set(0, ['JavaScript', 'value']);
return js_table;
})(),

View File

@ -12,6 +12,7 @@ let tableTypes = {
"eqref": kWasmEqRef,
"structref": kWasmStructRef,
"arrayref": kWasmArrayRef,
"i31ref": kWasmI31Ref,
};
// Test table consistency check.
@ -115,11 +116,13 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
builder.addFunction("createI31", i31Sig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprI31New])
.exportFunc();
let structSig = typeName != "arrayref" ? creatorSig : creatorAnySig;
let structSig = typeName != "arrayref" && typeName != "i31ref"
? creatorSig : creatorAnySig;
builder.addFunction("createStruct", structSig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprStructNew, struct])
.exportFunc();
let arraySig = typeName != "structref" ? creatorSig : creatorAnySig;
let arraySig = typeName != "structref" && typeName != "i31ref"
? creatorSig : creatorAnySig;
builder.addFunction("createArray", arraySig)
.addBody([
kExprI32Const, 12,
@ -158,7 +161,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertSame(table.get(2), table.get(3)); // The same smi.
}
// Set struct.
if (typeName != "arrayref") {
if (typeName != "arrayref" && typeName != "i31ref") {
table.set(4, wasm.exported(wasm.createStruct));
assertSame(table.get(4), wasm.tableGet(4));
assertEquals(12, wasm.tableGetStructVal(4));
@ -168,7 +171,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertNotSame(table.get(4), table.get(5));
}
// Set array.
if (typeName != "structref") {
if (typeName != "structref" && typeName != "i31ref") {
table.set(6, wasm.exported(wasm.createArray));
assertSame(table.get(6), wasm.tableGet(6));
assertEquals(12, wasm.tableGetArrayVal(6));
@ -190,7 +193,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals(largeString, table.get(9));
}
if (typeName != "arrayref") {
if (typeName != "arrayref" && typeName != "i31ref") {
// Grow table with explicit value.
table.grow(2, wasm.exported(wasm.createStruct));
assertEquals(12, wasm.tableGetStructVal(size));
@ -205,6 +208,19 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals("Grow using a string", wasm.tableGet(14));
assertEquals("Grow using a string", table.get(14));
}
if (typeName == "i31ref" || typeName == "anyref") {
table.set(0, 123);
assertEquals(123, table.get(0));
table.set(1, -123);
assertEquals(-123, table.get(1));
if (typeName == "i31ref") {
assertThrows(() => table.set(0, 1 << 31), TypeError);
} else {
// anyref can reference boxed numbers as well.
table.set(0, 1 << 31)
assertEquals(1 << 31, table.get(0));
}
}
// Set from JS with wrapped wasm value of incompatible type.
let invalidValues = {
@ -212,6 +228,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
"eqref": [],
"structref": ["I31", "Array"],
"arrayref": ["I31", "Struct"],
"i31ref": ["Struct", "Array"],
};
for (let invalidType of invalidValues[typeName]) {
print(`Test invalid type ${invalidType} for ${typeName}`);

View File

@ -322,6 +322,41 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
assertEquals(1, instance.exports.null_getter(2));
})();
(function TestI31RefTable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let table = builder.addTable(kWasmI31Ref, 4, 4);
builder.addActiveElementSegment(
table, wasmI32Const(0),
[[...wasmI32Const(10), kGCPrefix, kExprI31New],
[...wasmI32Const(-42), kGCPrefix, kExprI31New],
[kExprRefNull, kI31RefCode]],
kWasmI31Ref);
builder.addFunction("i31GetI32", kSig_i_i)
.addBody([
kExprLocalGet, 0, kExprTableGet, 0,
kGCPrefix, kExprI31GetS])
.exportFunc();
builder.addFunction("i31GetNull", kSig_i_i)
.addBody([kExprLocalGet, 0, kExprTableGet, 0, kExprRefIsNull])
.exportFunc();
let instance = builder.instantiate({});
assertTrue(!!instance);
assertEquals(0, instance.exports.i31GetNull(0));
assertEquals(0, instance.exports.i31GetNull(1));
assertEquals(1, instance.exports.i31GetNull(2));
assertEquals(1, instance.exports.i31GetNull(3));
assertEquals(10, instance.exports.i31GetI32(0));
assertEquals(-42, instance.exports.i31GetI32(1));
assertTraps(kTrapNullDereference, () => instance.exports.i31GetI32(2));
assertTraps(kTrapNullDereference, () => instance.exports.i31GetI32(3));
})();
(function TestArrayRefTable() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();