[wasm-gc] Skip null-check for casts of any to non-nullable type

We can skip explicit null check for casts from any to a non-nullable
type as they have to perform an instance type check afterwards as part
of the cast and trap if they encounter a non-wasm object (null is not
a wasm object).
The same is true for type checks which fail on null.

Bug: v8:7748
Change-Id: I41ec225618a400feec5dab210fbf7c1bc2718c8f
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3981859
Reviewed-by: Manos Koukoutos <manoskouk@chromium.org>
Commit-Queue: Matthias Liedtke <mliedtke@chromium.org>
Cr-Commit-Position: refs/heads/main@{#83950}
This commit is contained in:
Matthias Liedtke 2022-10-26 18:34:36 +02:00 committed by V8 LUCI CQ
parent 53e69521f4
commit f1d16aebe4
2 changed files with 18 additions and 6 deletions

View File

@ -95,8 +95,12 @@ Reduction WasmGCLowering::ReduceWasmTypeCheck(Node* node) {
gasm_.InitializeEffectControl(effect_input, control_input); gasm_.InitializeEffectControl(effect_input, control_input);
auto end_label = gasm_.MakeLabel(MachineRepresentation::kWord32); auto end_label = gasm_.MakeLabel(MachineRepresentation::kWord32);
bool is_cast_from_any = config.from.is_reference_to(wasm::HeapType::kAny);
if (object_can_be_null) { // Skip the null check if casting from any and if null results in check
// failure. In that case the instance type check will identify null as not
// being a wasm object and return 0 (failure).
if (object_can_be_null && (!is_cast_from_any || config.to.is_nullable())) {
const int kResult = config.to.is_nullable() ? 1 : 0; const int kResult = config.to.is_nullable() ? 1 : 0;
gasm_.GotoIf(gasm_.TaggedEqual(object, Null()), &end_label, gasm_.GotoIf(gasm_.TaggedEqual(object, Null()), &end_label,
BranchHint::kFalse, gasm_.Int32Constant(kResult)); BranchHint::kFalse, gasm_.Int32Constant(kResult));
@ -114,7 +118,7 @@ Reduction WasmGCLowering::ReduceWasmTypeCheck(Node* node) {
gasm_.Int32Constant(1)); gasm_.Int32Constant(1));
// Check if map instance type identifies a wasm object. // Check if map instance type identifies a wasm object.
if (config.from.is_reference_to(wasm::HeapType::kAny)) { if (is_cast_from_any) {
Node* is_wasm_obj = gasm_.IsDataRefMap(map); Node* is_wasm_obj = gasm_.IsDataRefMap(map);
gasm_.GotoIfNot(is_wasm_obj, &end_label, BranchHint::kTrue, gasm_.GotoIfNot(is_wasm_obj, &end_label, BranchHint::kTrue,
gasm_.Int32Constant(0)); gasm_.Int32Constant(0));
@ -166,8 +170,12 @@ Reduction WasmGCLowering::ReduceWasmTypeCast(Node* node) {
gasm_.InitializeEffectControl(effect_input, control_input); gasm_.InitializeEffectControl(effect_input, control_input);
auto end_label = gasm_.MakeLabel(); auto end_label = gasm_.MakeLabel();
bool is_cast_from_any = config.from.is_reference_to(wasm::HeapType::kAny);
if (object_can_be_null) { // Skip the null check if casting from any and if null results in check
// failure. In that case the instance type check will identify null as not
// being a wasm object and trap.
if (object_can_be_null && (!is_cast_from_any || config.to.is_nullable())) {
Node* is_null = gasm_.TaggedEqual(object, Null()); Node* is_null = gasm_.TaggedEqual(object, Null());
if (config.to.is_nullable()) { if (config.to.is_nullable()) {
gasm_.GotoIf(is_null, &end_label, BranchHint::kFalse); gasm_.GotoIf(is_null, &end_label, BranchHint::kFalse);
@ -187,7 +195,7 @@ Reduction WasmGCLowering::ReduceWasmTypeCast(Node* node) {
gasm_.GotoIf(gasm_.TaggedEqual(map, rtt), &end_label, BranchHint::kTrue); gasm_.GotoIf(gasm_.TaggedEqual(map, rtt), &end_label, BranchHint::kTrue);
// Check if map instance type identifies a wasm object. // Check if map instance type identifies a wasm object.
if (config.from.is_reference_to(wasm::HeapType::kAny)) { if (is_cast_from_any) {
Node* is_wasm_obj = gasm_.IsDataRefMap(map); Node* is_wasm_obj = gasm_.IsDataRefMap(map);
gasm_.TrapUnless(is_wasm_obj, TrapId::kTrapIllegalCast); gasm_.TrapUnless(is_wasm_obj, TrapId::kTrapIllegalCast);
} }

View File

@ -5848,8 +5848,12 @@ class LiftoffCompiler {
NullSucceeds null_succeeds, NullSucceeds null_succeeds,
const FreezeCacheState& frozen) { const FreezeCacheState& frozen) {
Label match; Label match;
bool is_cast_from_any = obj_type.is_reference_to(HeapType::kAny);
if (obj_type.is_nullable()) { // Skip the null check if casting from any and not {null_succeeds}.
// In that case the instance type check will identify null as not being a
// wasm object and fail.
if (obj_type.is_nullable() && (!is_cast_from_any || null_succeeds)) {
__ emit_cond_jump(kEqual, null_succeeds ? &match : no_match, __ emit_cond_jump(kEqual, null_succeeds ? &match : no_match,
obj_type.kind(), obj_reg, scratch_null, frozen); obj_type.kind(), obj_reg, scratch_null, frozen);
} }
@ -5876,7 +5880,7 @@ class LiftoffCompiler {
// rtt. // rtt.
__ emit_cond_jump(kEqual, &match, rtt_type.kind(), tmp1, rtt_reg, frozen); __ emit_cond_jump(kEqual, &match, rtt_type.kind(), tmp1, rtt_reg, frozen);
if (obj_type.is_reference_to(HeapType::kAny)) { if (is_cast_from_any) {
// Check for map being a map for a wasm object (struct, array, func). // Check for map being a map for a wasm object (struct, array, func).
__ Load(LiftoffRegister(scratch2), tmp1, no_reg, __ Load(LiftoffRegister(scratch2), tmp1, no_reg,
wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset), wasm::ObjectAccess::ToTagged(Map::kInstanceTypeOffset),