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

[wasm-gc] Introduce minimum supertype length

We introduce a minimum length for the supertype array of gc maps. When
the depth of the rtt is known to be smaller than that length, we can
type check without bounds checking the supertype array of the object
map.

Bug: v8:7748, v8:11510
Change-Id: I88e67871040a8c4dd219e48a84527f7f3f3d0a96
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3312487Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78280}
parent 6114d098
......@@ -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))));
// 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<uint32_t>(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());
......
......@@ -1474,12 +1474,24 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
Handle<ArrayList> subtypes = ArrayList::New(isolate(), 0);
Handle<FixedArray> 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<FixedArray> 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<WasmTypeInfo> 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);
......
......@@ -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.
if (rtt.type.has_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);
if (rtt.type.has_depth()) {
__ 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);
......
......@@ -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
......
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