[wasm-gc] ref.cast null: Always produces a null type independent of input type

This is required to be spec-compliant.
The previously implemented behavior was more relaxed allowing one to use
`ref.cast null` on non-nullable inputs and still getting a non-nullable
result on cast success.

Bug: v8:7748
Change-Id: I1297314389b0445a7c8d5a74f37d07a723d7a133
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4091549
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#84776}
This commit is contained in:
Matthias Liedtke 2022-12-12 10:44:10 +01:00 committed by V8 LUCI CQ
parent d310532598
commit 1bf670ef20
2 changed files with 62 additions and 3 deletions

View File

@ -4898,9 +4898,7 @@ class WasmFullDecoder : public WasmDecoder<ValidationTag, decoding_mode> {
bool null_succeeds = opcode == kExprRefCastNull;
Value value = CreateValue(ValueType::RefMaybeNull(
imm.type, (obj.type.is_bottom() || !null_succeeds)
? kNonNullable
: obj.type.nullability()));
target_type, null_succeeds ? kNullable : kNonNullable));
if (current_code_reachable_and_ok_) {
// This logic ensures that code generation can assume that functions
// can only be cast to function types, and data objects to data types.

View File

@ -0,0 +1,61 @@
// 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-gc --no-wasm-gc-structref-as-dataref
d8.file.execute('test/mjsunit/wasm/wasm-module-builder.js');
(function TestRefCastNullReturnsNullTypeForNonNullInput() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let consumeRefI31 =
builder.addFunction(`consumeRefI31`,
makeSig([wasmRefType(kWasmI31Ref)], []))
.addBody([]);
builder.addFunction(`refCastRemovesNullability`,
makeSig([kWasmExternRef], []))
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprExternInternalize,
kExprRefAsNonNull,
kGCPrefix, kExprRefCastNull, kI31RefCode,
// ref.cast null pushes a nullable value on the stack even though its input
// was non-nullable, therefore this call is not spec-compliant.
kExprCallFunction, consumeRefI31.index,
]).exportFunc();
assertThrows(() => builder.instantiate(), WebAssembly.CompileError,
/expected type \(ref i31\), found .* type i31ref/);
})();
(function TestRefCastRemovesNullability() {
print(arguments.callee.name);
let builder = new WasmModuleBuilder();
let i31ToI32 =
builder.addFunction(`i31ToI32`,
makeSig([wasmRefType(kWasmI31Ref)], [kWasmI32]))
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprI31GetS
]);
builder.addFunction(`refCastRemovesNullability`,
makeSig([kWasmExternRef], [kWasmI32]))
.addBody([
kExprLocalGet, 0,
kGCPrefix, kExprExternInternalize,
kGCPrefix, kExprRefCast, kI31RefCode,
// ref.cast pushes a non-nullable value on the stack even for a nullable
// input value as the instruction traps on null.
kExprCallFunction, i31ToI32.index,
]).exportFunc();
let wasm = builder.instantiate().exports;
assertEquals(42, wasm.refCastRemovesNullability(42));
assertEquals(-1, wasm.refCastRemovesNullability(-1));
assertTraps(kTrapIllegalCast, () => wasm.refCastRemovesNullability(null));
})();