[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/+/3312487
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#78280}
This commit is contained in:
Manos Koukoutos 2021-12-02 13:51:32 +00:00 committed by V8 LUCI CQ
parent 6114d09840
commit dc01b43616
4 changed files with 45 additions and 16 deletions

View File

@ -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<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());

View File

@ -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);

View File

@ -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);

View File

@ -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