Commit 1ac45dd9 authored by Manos Koukoutos's avatar Manos Koukoutos Committed by V8 LUCI CQ

[wasm-gc] Optionally skip null checks

Bug: v8:7748
Change-Id: Ia277cf58a0eea431c4f19198914c1539fd03bc06
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3207898
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Cr-Commit-Position: refs/heads/main@{#77264}
parent 5889deb1
...@@ -611,8 +611,10 @@ Node* WasmGraphBuilder::RefFunc(uint32_t function_index) { ...@@ -611,8 +611,10 @@ Node* WasmGraphBuilder::RefFunc(uint32_t function_index) {
Node* WasmGraphBuilder::RefAsNonNull(Node* arg, Node* WasmGraphBuilder::RefAsNonNull(Node* arg,
wasm::WasmCodePosition position) { wasm::WasmCodePosition position) {
TrapIfTrue(wasm::kTrapIllegalCast, gasm_->WordEqual(arg, RefNull()), if (!FLAG_experimental_wasm_skip_null_checks) {
position); TrapIfTrue(wasm::kTrapIllegalCast, gasm_->WordEqual(arg, RefNull()),
position);
}
return arg; return arg;
} }
......
...@@ -2456,7 +2456,7 @@ class LiftoffCompiler { ...@@ -2456,7 +2456,7 @@ class LiftoffCompiler {
LiftoffRegList pinned; LiftoffRegList pinned;
LiftoffRegister obj = pinned.set(__ PopToRegister(pinned)); LiftoffRegister obj = pinned.set(__ PopToRegister(pinned));
Label* trap_label = Label* trap_label =
AddOutOfLineTrap(decoder, WasmCode::kThrowWasmTrapNullDereference); AddOutOfLineTrap(decoder, WasmCode::kThrowWasmTrapIllegalCast);
LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned); LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned);
LoadNullValue(null.gp(), pinned); LoadNullValue(null.gp(), pinned);
__ emit_cond_jump(kUnequal, trap_label, kOptRef, obj.gp(), null.gp()); __ emit_cond_jump(kUnequal, trap_label, kOptRef, obj.gp(), null.gp());
...@@ -6030,7 +6030,7 @@ class LiftoffCompiler { ...@@ -6030,7 +6030,7 @@ class LiftoffCompiler {
void MaybeEmitNullCheck(FullDecoder* decoder, Register object, void MaybeEmitNullCheck(FullDecoder* decoder, Register object,
LiftoffRegList pinned, ValueType type) { LiftoffRegList pinned, ValueType type) {
if (!type.is_nullable()) return; if (FLAG_experimental_wasm_skip_null_checks || !type.is_nullable()) return;
Label* trap_label = Label* trap_label =
AddOutOfLineTrap(decoder, WasmCode::kThrowWasmTrapNullDereference); AddOutOfLineTrap(decoder, WasmCode::kThrowWasmTrapNullDereference);
LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned); LiftoffRegister null = __ GetUnusedRegister(kGpReg, pinned);
......
...@@ -1754,8 +1754,9 @@ class WasmGraphBuildingInterface { ...@@ -1754,8 +1754,9 @@ class WasmGraphBuildingInterface {
CheckForNull NullCheckFor(ValueType type) { CheckForNull NullCheckFor(ValueType type) {
DCHECK(type.is_object_reference()); DCHECK(type.is_object_reference());
return type.is_nullable() ? CheckForNull::kWithNullCheck return (!FLAG_experimental_wasm_skip_null_checks && type.is_nullable())
: CheckForNull::kWithoutNullCheck; ? CheckForNull::kWithNullCheck
: CheckForNull::kWithoutNullCheck;
} }
}; };
......
...@@ -35,6 +35,9 @@ ...@@ -35,6 +35,9 @@
V(assume_ref_cast_succeeds, \ V(assume_ref_cast_succeeds, \
"assume ref.cast always succeeds and skip the related type check " \ "assume ref.cast always succeeds and skip the related type check " \
"(unsafe)", \ "(unsafe)", \
false) \
V(skip_null_checks, \
"skip null checks for call.ref and array and struct operations (unsafe)", \
false) \ false) \
\ \
/* Typed function references proposal. */ \ /* Typed function references proposal. */ \
......
...@@ -317,8 +317,7 @@ WASM_COMPILED_EXEC_TEST(WasmBasicStruct) { ...@@ -317,8 +317,7 @@ WASM_COMPILED_EXEC_TEST(WasmBasicStruct) {
tester.CheckResult(kSet, -99); tester.CheckResult(kSet, -99);
} }
// Test struct.set, ref.as_non_null, // Test struct.get, ref.as_non_null and ref-typed globals.
// struct refs types in globals and if-results.
WASM_COMPILED_EXEC_TEST(WasmRefAsNonNull) { WASM_COMPILED_EXEC_TEST(WasmRefAsNonNull) {
WasmGCTester tester(execution_tier); WasmGCTester tester(execution_tier);
const byte type_index = const byte type_index =
...@@ -332,21 +331,48 @@ WASM_COMPILED_EXEC_TEST(WasmRefAsNonNull) { ...@@ -332,21 +331,48 @@ WASM_COMPILED_EXEC_TEST(WasmRefAsNonNull) {
WasmInitExpr::RefNullConst( WasmInitExpr::RefNullConst(
static_cast<HeapType::Representation>(type_index))); static_cast<HeapType::Representation>(type_index)));
const byte field_index = 0; const byte field_index = 0;
const byte kFunc = tester.DefineFunction( const byte kNonNull = tester.DefineFunction(
tester.sigs.i_v(), {}, tester.sigs.i_v(), {},
{WASM_GLOBAL_SET( {WASM_GLOBAL_SET(
global_index, global_index,
WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(55), WASM_I32V(66), WASM_STRUCT_NEW_WITH_RTT(type_index, WASM_I32V(55), WASM_I32V(66),
WASM_RTT_CANON(type_index))), WASM_RTT_CANON(type_index))),
WASM_STRUCT_GET( WASM_STRUCT_GET(type_index, field_index,
type_index, field_index, WASM_REF_AS_NON_NULL(WASM_GLOBAL_GET(global_index))),
WASM_REF_AS_NON_NULL(WASM_IF_ELSE_R(kOptRefType, WASM_I32V(1),
WASM_GLOBAL_GET(global_index),
WASM_REF_NULL(type_index)))),
kExprEnd}); kExprEnd});
const byte kNull = tester.DefineFunction(
tester.sigs.i_v(), {},
{WASM_GLOBAL_SET(global_index, WASM_REF_NULL(type_index)),
WASM_STRUCT_GET(type_index, field_index,
WASM_REF_AS_NON_NULL(WASM_GLOBAL_GET(global_index))),
kExprEnd});
tester.CompileModule();
tester.CheckResult(kNonNull, 55);
tester.CheckHasThrown(kNull);
}
WASM_COMPILED_EXEC_TEST(WasmRefAsNonNullSkipCheck) {
FlagScope<bool> no_check(&FLAG_experimental_wasm_skip_null_checks, true);
WasmGCTester tester(execution_tier);
const byte type_index =
tester.DefineStruct({F(kWasmI32, true), F(kWasmI32, true)});
ValueType kRefType = ref(type_index);
FunctionSig sig_q_v(1, 0, &kRefType);
const byte global_index =
tester.AddGlobal(optref(type_index), true,
WasmInitExpr::RefNullConst(
static_cast<HeapType::Representation>(type_index)));
const byte kFunc = tester.DefineFunction(
&sig_q_v, {},
{WASM_GLOBAL_SET(global_index, WASM_REF_NULL(type_index)),
WASM_REF_AS_NON_NULL(WASM_GLOBAL_GET(global_index)), kExprEnd});
tester.CompileModule(); tester.CompileModule();
tester.CheckResult(kFunc, 55); Handle<Object> result = tester.GetResultObject(kFunc).ToHandleChecked();
// Without null checks, ref.as_non_null can actually return null.
CHECK(result->IsNull());
} }
WASM_COMPILED_EXEC_TEST(WasmBrOnNull) { WASM_COMPILED_EXEC_TEST(WasmBrOnNull) {
......
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