Commit b82cc92e authored by Matthias Liedtke's avatar Matthias Liedtke Committed by V8 LUCI CQ

[wasm-gc] Fix table default ref value

- fix handling of undefined for non-externref tables
- add test for non-nullable ref table

Bug: v8:7748
Change-Id: I3f0f3aa68eb43208aea84cb8f21b37a539e14d26
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3862206
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82836}
parent d09f280f
......@@ -1116,11 +1116,13 @@ bool GetInitialOrMinimumProperty(v8::Isolate* isolate, ErrorThrower* thrower,
namespace {
i::Handle<i::Object> DefaultReferenceValue(i::Isolate* isolate,
i::wasm::ValueType type) {
if (type == i::wasm::kWasmFuncRef) {
return isolate->factory()->null_value();
}
if (type.is_reference()) {
return isolate->factory()->undefined_value();
// Use undefined for JS type (externref) but null for wasm types as wasm
// does not know undefined.
if (type.heap_representation() == i::wasm::HeapType::kExtern) {
return isolate->factory()->undefined_value();
}
return isolate->factory()->null_value();
}
UNREACHABLE();
}
......@@ -2237,6 +2239,10 @@ void WebAssemblyTableGrow(const v8::FunctionCallbackInfo<v8::Value>& args) {
thrower.TypeError("Argument 1 must be a valid type for the table");
return;
}
} else if (receiver->type().is_non_nullable()) {
thrower.TypeError(
"Argument 1 must be specified for non-nullable element type");
return;
} else {
init_value = DefaultReferenceValue(i_isolate, receiver->type());
}
......
......@@ -49,6 +49,7 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
});
let creatorSig = builder.addType(makeSig([], [type]));
let creatorAnySig = builder.addType(makeSig([], [kWasmAnyRef]));
let struct = builder.addStruct([makeField(kWasmI32, false)]);
let array = builder.addArray(kWasmI32, true);
......@@ -96,6 +97,14 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
kGCPrefix, kExprExternExternalize,
])
.exportFunc();
builder.addFunction("exportedAny",
makeSig([wasmRefType(creatorAnySig)], [kWasmExternRef]))
.addBody([
kExprLocalGet, 0,
kExprCallRef,
kGCPrefix, kExprExternExternalize,
])
.exportFunc();
let blockSig = builder.addType(makeSig([kWasmAnyRef], [kWasmEqRef]));
let castExternToEqRef = [
......@@ -123,16 +132,15 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
builder.addFunction("createNull", creatorSig)
.addBody([kExprRefNull, kNullRefCode])
.exportFunc();
if (typeName != "dataref" && typeName != "arrayref") {
builder.addFunction("createI31", creatorSig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprI31New])
.exportFunc();
}
if (typeName != "arrayref") {
builder.addFunction("createStruct", creatorSig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprStructNew, struct])
.exportFunc();
}
let i31Sig = typeName != "dataref" && typeName != "arrayref"
? creatorSig : creatorAnySig;
builder.addFunction("createI31", i31Sig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprI31New])
.exportFunc();
let structSig = typeName != "arrayref" ? creatorSig : creatorAnySig;
builder.addFunction("createStruct", structSig)
.addBody([kExprI32Const, 12, kGCPrefix, kExprStructNew, struct])
.exportFunc();
builder.addFunction("createArray", creatorSig)
.addBody([
kExprI32Const, 12,
......@@ -188,5 +196,22 @@ for (let [typeName, type] of Object.entries(tableTypes)) {
assertEquals(12, wasm.tableGetStructVal(size));
assertEquals(12, wasm.tableGetStructVal(size + 1));
assertTraps(kTrapTableOutOfBounds, () => wasm.tableGetStructVal(size + 2));
// Grow by 1 without initial value.
table.grow(1, null);
table.grow(1, undefined);
}
// Set from JS with wrapped wasm value of incompatible type.
let invalidValues = {
"anyref": [],
"eqref": [],
"dataref": ["I31"],
"arrayref": ["I31", "Struct"],
};
for (let invalidType of invalidValues[typeName]) {
print(`Test invalid type ${invalidType} for ${typeName}`);
let invalid_value = wasm.exportedAny(wasm[`create${invalidType}`]);
assertThrows(() => table.grow(1, invalid_value), TypeError);
assertThrows(() => table.set(1, invalid_value), TypeError);
}
}
......@@ -160,21 +160,21 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
[kExprRefNull, kEqRefCode]],
kWasmAnyRef);
// return ...static_cast<array_type>(table[0])(local_0)
builder.addFunction("array_getter", kSig_ii_i)
// 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, kExprRefCastStatic, array_type,
kExprLocalSet, 1,
kExprLocalGet, 1,
kExprLocalSet, 0,
kExprLocalGet, 0,
...wasmI32Const(0), kGCPrefix, kExprArrayGet, array_type,
kExprLocalGet, 1,
kExprLocalGet, 0,
...wasmI32Const(1), kGCPrefix, kExprArrayGet, array_type])
.exportFunc();
// return static_cast<i31>(table[1])(local_0, local_1)
// return static_cast<i31>(table[1])
builder.addFunction("i31_getter", kSig_i_v)
.addBody([
kExprI32Const, 1, kExprTableGet, 0,
......@@ -199,8 +199,93 @@ d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
assertTrue(!!instance);
assertEquals([111, 222], instance.exports.array_getter(42));
assertEquals(-31, instance.exports.i31_getter(12, 19));
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, kExprRefCastStatic, 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,
kGCPrefix, kExprRefAsData, kGCPrefix, kExprRefCastStatic, 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));
assertThrows(() => wasmTable.set(4, undefined), TypeError,
/Argument 1 is invalid/);
assertThrows(() => wasmTable.set(4, null), TypeError,
/Argument 1 is invalid/);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment