diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc index 12eec5804c..8ac4d06f0c 100644 --- a/src/compiler/wasm-compiler.cc +++ b/src/compiler/wasm-compiler.cc @@ -5820,19 +5820,27 @@ void WasmGraphBuilder::TypeCheck( DCHECK(config.reference_kind == kArrayOrStruct); + // First, check if types happen to be equal. This has been shown to give large + // speedups. callbacks.succeed_if(gasm_->TaggedEqual(map, rtt), BranchHint::kTrue); Node* type_info = gasm_->LoadWasmTypeInfo(map); Node* supertypes = gasm_->LoadSupertypes(type_info); - Node* supertypes_length = - BuildChangeSmiToIntPtr(gasm_->LoadFixedArrayLengthAsSmi(supertypes)); Node* rtt_depth = config.rtt_depth >= 0 ? gasm_->IntPtrConstant(config.rtt_depth) : BuildChangeSmiToIntPtr(gasm_->LoadFixedArrayLengthAsSmi( gasm_->LoadSupertypes(gasm_->LoadWasmTypeInfo(rtt)))); - callbacks.fail_if_not(gasm_->UintLessThan(rtt_depth, supertypes_length), - BranchHint::kTrue); + // If the depth of the rtt is known to be less that the minimum supertype + // array length, we can access the supertype without bounds-checking the + // supertype array. + if (config.rtt_depth < 0 || static_cast(config.rtt_depth) >= + wasm::kMinimumSupertypeArraySize) { + Node* supertypes_length = + BuildChangeSmiToIntPtr(gasm_->LoadFixedArrayLengthAsSmi(supertypes)); + callbacks.fail_if_not(gasm_->UintLessThan(rtt_depth, supertypes_length), + BranchHint::kTrue); + } Node* maybe_match = gasm_->LoadFixedArrayElement( supertypes, rtt_depth, MachineType::TaggedPointer()); diff --git a/src/heap/factory.cc b/src/heap/factory.cc index 4e7276b7d4..9e05c52472 100644 --- a/src/heap/factory.cc +++ b/src/heap/factory.cc @@ -1474,12 +1474,24 @@ Handle Factory::NewWasmTypeInfo( Handle subtypes = ArrayList::New(isolate(), 0); Handle supertypes; if (opt_parent.is_null()) { - supertypes = NewFixedArray(0); + supertypes = NewFixedArray(wasm::kMinimumSupertypeArraySize); + for (int i = 0; i < supertypes->length(); i++) { + supertypes->set(i, *undefined_value()); + } } else { - supertypes = CopyArrayAndGrow( - handle(opt_parent->wasm_type_info().supertypes(), isolate()), 1, - AllocationType::kOld); - supertypes->set(supertypes->length() - 1, *opt_parent); + Handle parent_supertypes = + handle(opt_parent->wasm_type_info().supertypes(), isolate()); + int last_defined_index = parent_supertypes->length() - 1; + while (last_defined_index >= 0 && + parent_supertypes->get(last_defined_index).IsUndefined()) { + last_defined_index--; + } + if (last_defined_index == parent_supertypes->length() - 1) { + supertypes = CopyArrayAndGrow(parent_supertypes, 1, AllocationType::kOld); + } else { + supertypes = CopyFixedArray(parent_supertypes); + } + supertypes->set(last_defined_index + 1, *opt_parent); } Map map = *wasm_type_info_map(); WasmTypeInfo result = WasmTypeInfo::cast(AllocateRawWithImmortalMap( @@ -1487,7 +1499,7 @@ Handle Factory::NewWasmTypeInfo( DisallowGarbageCollection no_gc; result.AllocateExternalPointerEntries(isolate()); result.set_foreign_address(isolate(), type_address); - result.set_supertypes(*supertypes, SKIP_WRITE_BARRIER); + result.set_supertypes(*supertypes); result.set_subtypes(*subtypes); result.set_instance_size(instance_size_bytes); result.set_instance(*instance); diff --git a/src/wasm/baseline/liftoff-compiler.cc b/src/wasm/baseline/liftoff-compiler.cc index 4fca6f5f76..089996884d 100644 --- a/src/wasm/baseline/liftoff-compiler.cc +++ b/src/wasm/baseline/liftoff-compiler.cc @@ -5470,17 +5470,19 @@ class LiftoffCompiler { constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged( Map::kConstructorOrBackPointerOrNativeContextOffset); __ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset, pinned); - // Step 2: load the super types list into {tmp1}. + // Step 2: load the supertypes list into {tmp1}. constexpr int kSuperTypesOffset = wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset); __ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kSuperTypesOffset, pinned); - // Step 3: check the list's length. - LiftoffRegister list_length = tmp2; - __ LoadFixedArrayLengthAsInt32(list_length, tmp1.gp(), pinned); if (rtt.type.has_depth()) { - __ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(), - rtt.type.depth()); + // Step 3: check the list's length if needed. + if (rtt.type.depth() >= kMinimumSupertypeArraySize) { + LiftoffRegister list_length = tmp2; + __ LoadFixedArrayLengthAsInt32(list_length, tmp1.gp(), pinned); + __ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(), + rtt.type.depth()); + } // Step 4: load the candidate list slot into {tmp1}, and compare it. __ LoadTaggedPointer( tmp1.gp(), tmp1.gp(), no_reg, @@ -5489,6 +5491,9 @@ class LiftoffCompiler { __ emit_cond_jump(kUnequal, no_match, rtt.type.kind(), tmp1.gp(), rtt_reg.gp()); } else { + // Step 3: if rtt's depth is unknown, we invoke a builtin to compute the + // result, as we might not have enough available registers. + // Preserve {obj_reg} across the call. LiftoffRegList saved_regs = LiftoffRegList::ForRegs(obj_reg); __ PushRegisters(saved_regs); diff --git a/src/wasm/wasm-constants.h b/src/wasm/wasm-constants.h index a9b66876d2..f5bce0a5b4 100644 --- a/src/wasm/wasm-constants.h +++ b/src/wasm/wasm-constants.h @@ -160,6 +160,10 @@ constexpr int kAnonymousFuncIndex = -1; // often enough. constexpr uint32_t kGenericWrapperBudget = 1000; +// The minimum length of supertype arrays for wasm-gc types. Having a size > 0 +// gives up some module size for faster access to the supertypes. +constexpr uint32_t kMinimumSupertypeArraySize = 3; + #if V8_TARGET_ARCH_X64 constexpr int32_t kOSRTargetOffset = 5 * kSystemPointerSize; #endif