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

[wasm-gc] Inline supertypes into TypeInfo

This saves one indirection when fetching the supertype array for
type checks.

Bug: v8:7748
Change-Id: I41ec5a190c1ccdd9112869c7cdf1748bef4b359a
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3688405Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Manos Koukoutos <manoskouk@chromium.org>
Cr-Commit-Position: refs/heads/main@{#81012}
parent 31ece3e9
...@@ -419,7 +419,7 @@ builtin WasmSubtypeCheck(objectSupertypes: FixedArray, rtt: Map): int32 { ...@@ -419,7 +419,7 @@ builtin WasmSubtypeCheck(objectSupertypes: FixedArray, rtt: Map): int32 {
const rttSupertypeLength: Smi = const rttSupertypeLength: Smi =
%RawDownCast<WasmTypeInfo>( %RawDownCast<WasmTypeInfo>(
rtt.constructor_or_back_pointer_or_native_context) rtt.constructor_or_back_pointer_or_native_context)
.supertypes.length; .supertypes_length;
if (objectSupertypes.length <= rttSupertypeLength) { if (objectSupertypes.length <= rttSupertypeLength) {
return 0; return 0;
......
...@@ -101,21 +101,25 @@ Reduction WasmGCLowering::ReduceWasmTypeCheck(Node* node) { ...@@ -101,21 +101,25 @@ Reduction WasmGCLowering::ReduceWasmTypeCheck(Node* node) {
gasm_.Int32Constant(1)); gasm_.Int32Constant(1));
Node* type_info = gasm_.LoadWasmTypeInfo(map); Node* type_info = gasm_.LoadWasmTypeInfo(map);
Node* supertypes = gasm_.LoadSupertypes(type_info);
DCHECK_GE(rtt_depth, 0); DCHECK_GE(rtt_depth, 0);
Node* rtt_depth_node = gasm_.IntPtrConstant(rtt_depth);
// If the depth of the rtt is known to be less that the minimum supertype // 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 // array length, we can access the supertype without bounds-checking the
// supertype array. // supertype array.
if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) { if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) {
Node* supertypes_length = gasm_.BuildChangeSmiToIntPtr( Node* supertypes_length =
gasm_.LoadFixedArrayLengthAsSmi(supertypes)); gasm_.BuildChangeSmiToIntPtr(gasm_.LoadImmutableFromObject(
gasm_.GotoIfNot(gasm_.UintLessThan(rtt_depth_node, supertypes_length), MachineType::TaggedSigned(), type_info,
&end_label, BranchHint::kTrue, gasm_.Int32Constant(0)); wasm::ObjectAccess::ToTagged(
WasmTypeInfo::kSupertypesLengthOffset)));
gasm_.GotoIfNot(
gasm_.UintLessThan(gasm_.IntPtrConstant(rtt_depth), supertypes_length),
&end_label, BranchHint::kTrue, gasm_.Int32Constant(0));
} }
Node* maybe_match = gasm_.LoadImmutableFixedArrayElement( Node* maybe_match = gasm_.LoadImmutableFromObject(
supertypes, rtt_depth_node, MachineType::TaggedPointer()); MachineType::TaggedPointer(), type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset +
kTaggedSize * rtt_depth));
gasm_.Goto(&end_label, gasm_.TaggedEqual(maybe_match, rtt)); gasm_.Goto(&end_label, gasm_.TaggedEqual(maybe_match, rtt));
...@@ -153,21 +157,25 @@ Reduction WasmGCLowering::ReduceWasmTypeCast(Node* node) { ...@@ -153,21 +157,25 @@ 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);
Node* type_info = gasm_.LoadWasmTypeInfo(map); Node* type_info = gasm_.LoadWasmTypeInfo(map);
Node* supertypes = gasm_.LoadSupertypes(type_info);
DCHECK_GE(rtt_depth, 0); DCHECK_GE(rtt_depth, 0);
Node* rtt_depth_node = gasm_.IntPtrConstant(rtt_depth);
// If the depth of the rtt is known to be less that the minimum supertype // 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 // array length, we can access the supertype without bounds-checking the
// supertype array. // supertype array.
if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) { if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) {
Node* supertypes_length = gasm_.BuildChangeSmiToIntPtr( Node* supertypes_length =
gasm_.LoadFixedArrayLengthAsSmi(supertypes)); gasm_.BuildChangeSmiToIntPtr(gasm_.LoadImmutableFromObject(
gasm_.TrapUnless(gasm_.UintLessThan(rtt_depth_node, supertypes_length), MachineType::TaggedSigned(), type_info,
TrapId::kTrapIllegalCast); wasm::ObjectAccess::ToTagged(
WasmTypeInfo::kSupertypesLengthOffset)));
gasm_.TrapUnless(
gasm_.UintLessThan(gasm_.IntPtrConstant(rtt_depth), supertypes_length),
TrapId::kTrapIllegalCast);
} }
Node* maybe_match = gasm_.LoadImmutableFixedArrayElement( Node* maybe_match = gasm_.LoadImmutableFromObject(
supertypes, rtt_depth_node, MachineType::TaggedPointer()); MachineType::TaggedPointer(), type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset +
kTaggedSize * rtt_depth));
gasm_.TrapUnless(gasm_.TaggedEqual(maybe_match, rtt), gasm_.TrapUnless(gasm_.TaggedEqual(maybe_match, rtt),
TrapId::kTrapIllegalCast); TrapId::kTrapIllegalCast);
......
...@@ -215,12 +215,6 @@ Node* WasmGraphAssembler::LoadWasmTypeInfo(Node* map) { ...@@ -215,12 +215,6 @@ Node* WasmGraphAssembler::LoadWasmTypeInfo(Node* map) {
wasm::ObjectAccess::ToTagged(offset)); wasm::ObjectAccess::ToTagged(offset));
} }
Node* WasmGraphAssembler::LoadSupertypes(Node* wasm_type_info) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), wasm_type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset));
}
// FixedArrays. // FixedArrays.
Node* WasmGraphAssembler::LoadFixedArrayLengthAsSmi(Node* fixed_array) { Node* WasmGraphAssembler::LoadFixedArrayLengthAsSmi(Node* fixed_array) {
......
...@@ -170,8 +170,6 @@ class WasmGraphAssembler : public GraphAssembler { ...@@ -170,8 +170,6 @@ class WasmGraphAssembler : public GraphAssembler {
Node* LoadWasmTypeInfo(Node* map); Node* LoadWasmTypeInfo(Node* map);
Node* LoadSupertypes(Node* wasm_type_info);
// FixedArrays. // FixedArrays.
Node* LoadFixedArrayLengthAsSmi(Node* fixed_array); Node* LoadFixedArrayLengthAsSmi(Node* fixed_array);
......
...@@ -1829,7 +1829,11 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) { ...@@ -1829,7 +1829,11 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) {
void WasmTypeInfo::WasmTypeInfoPrint(std::ostream& os) { void WasmTypeInfo::WasmTypeInfoPrint(std::ostream& os) {
PrintHeader(os, "WasmTypeInfo"); PrintHeader(os, "WasmTypeInfo");
os << "\n - type address: " << reinterpret_cast<void*>(foreign_address()); os << "\n - type address: " << reinterpret_cast<void*>(foreign_address());
os << "\n - supertypes: " << Brief(supertypes()); // TODO(manoskouk): Print supertype info.
os << "\n - supertypes: ";
for (int i = 0; i < supertypes_length(); i++) {
os << "\n - " << Brief(supertypes(i));
}
os << "\n - instance: " << Brief(instance()); os << "\n - instance: " << Brief(instance());
os << "\n"; os << "\n";
} }
......
...@@ -1547,37 +1547,38 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo( ...@@ -1547,37 +1547,38 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
// (2) The object visitors need to read the WasmTypeInfo to find tagged // (2) The object visitors need to read the WasmTypeInfo to find tagged
// fields in Wasm structs; in the middle of a GC cycle that's only // fields in Wasm structs; in the middle of a GC cycle that's only
// safe to do if the WTI is in old space. // safe to do if the WTI is in old space.
// The supertypes list is constant after initialization, so we pretenure std::vector<Handle<Object>> supertypes;
// that too. The subtypes list, however, is expected to grow (and hence be
// replaced), so we don't pretenure it.
Handle<FixedArray> supertypes;
if (opt_parent.is_null()) { if (opt_parent.is_null()) {
supertypes = NewFixedArray(wasm::kMinimumSupertypeArraySize); supertypes.resize(wasm::kMinimumSupertypeArraySize, undefined_value());
for (int i = 0; i < supertypes->length(); i++) {
supertypes->set(i, *undefined_value());
}
} else { } else {
Handle<FixedArray> parent_supertypes = Handle<WasmTypeInfo> parent_type_info =
handle(opt_parent->wasm_type_info().supertypes(), isolate()); handle(opt_parent->wasm_type_info(), isolate());
int last_defined_index = parent_supertypes->length() - 1; int first_undefined_index = -1;
while (last_defined_index >= 0 && for (int i = 0; i < parent_type_info->supertypes_length(); i++) {
parent_supertypes->get(last_defined_index).IsUndefined()) { Handle<Object> supertype =
last_defined_index--; handle(parent_type_info->supertypes(i), isolate());
if (supertype->IsUndefined() && first_undefined_index == -1) {
first_undefined_index = i;
}
supertypes.emplace_back(supertype);
} }
if (last_defined_index == parent_supertypes->length() - 1) { if (first_undefined_index >= 0) {
supertypes = CopyArrayAndGrow(parent_supertypes, 1, AllocationType::kOld); supertypes[first_undefined_index] = opt_parent;
} else { } else {
supertypes = CopyFixedArray(parent_supertypes); supertypes.emplace_back(opt_parent);
} }
supertypes->set(last_defined_index + 1, *opt_parent);
} }
Map map = *wasm_type_info_map(); Map map = *wasm_type_info_map();
WasmTypeInfo result = WasmTypeInfo::cast(AllocateRawWithImmortalMap( WasmTypeInfo result = WasmTypeInfo::cast(AllocateRawWithImmortalMap(
map.instance_size(), AllocationType::kOld, map)); WasmTypeInfo::SizeFor(static_cast<int>(supertypes.size())),
AllocationType::kOld, map));
DisallowGarbageCollection no_gc; DisallowGarbageCollection no_gc;
result.set_supertypes_length(static_cast<int>(supertypes.size()));
for (size_t i = 0; i < supertypes.size(); i++) {
result.set_supertypes(static_cast<int>(i), *supertypes[i]);
}
result.AllocateExternalPointerEntries(isolate()); result.AllocateExternalPointerEntries(isolate());
result.set_foreign_address(isolate(), type_address); result.set_foreign_address(isolate(), type_address);
result.set_supertypes(*supertypes);
result.set_instance(*instance); result.set_instance(*instance);
return handle(result, isolate()); return handle(result, isolate());
} }
......
...@@ -517,7 +517,7 @@ bool Heap::CreateInitialMaps() { ...@@ -517,7 +517,7 @@ bool Heap::CreateInitialMaps() {
wasm_js_function_data) wasm_js_function_data)
IF_WASM(ALLOCATE_MAP, WASM_ON_FULFILLED_DATA_TYPE, IF_WASM(ALLOCATE_MAP, WASM_ON_FULFILLED_DATA_TYPE,
WasmOnFulfilledData::kSize, wasm_onfulfilled_data) WasmOnFulfilledData::kSize, wasm_onfulfilled_data)
IF_WASM(ALLOCATE_MAP, WASM_TYPE_INFO_TYPE, WasmTypeInfo::kSize, IF_WASM(ALLOCATE_MAP, WASM_TYPE_INFO_TYPE, kVariableSizeSentinel,
wasm_type_info) wasm_type_info)
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell) ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
......
...@@ -713,11 +713,14 @@ class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase { ...@@ -713,11 +713,14 @@ class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase {
ObjectVisitor* v) { ObjectVisitor* v) {
Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size, Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size,
v); v);
IteratePointer(obj, kSupertypesOffset, v);
IteratePointer(obj, kInstanceOffset, v); IteratePointer(obj, kInstanceOffset, v);
IteratePointers(obj, kSupertypesOffset, SizeOf(map, obj), v);
} }
static inline int SizeOf(Map map, HeapObject object) { return kSize; } static inline int SizeOf(Map map, HeapObject object) {
return kSupertypesOffset +
WasmTypeInfo::cast(object).supertypes_length() * kTaggedSize;
}
}; };
class WasmApiFunctionRef::BodyDescriptor final : public BodyDescriptorBase { class WasmApiFunctionRef::BodyDescriptor final : public BodyDescriptorBase {
......
...@@ -2288,11 +2288,15 @@ int HeapObject::SizeFromMap(Map map) const { ...@@ -2288,11 +2288,15 @@ int HeapObject::SizeFromMap(Map map) const {
CoverageInfo::unchecked_cast(*this).slot_count()); CoverageInfo::unchecked_cast(*this).slot_count());
} }
#if V8_ENABLE_WEBASSEMBLY #if V8_ENABLE_WEBASSEMBLY
if (instance_type == WASM_TYPE_INFO_TYPE) {
return WasmTypeInfo::SizeFor(
WasmTypeInfo::unchecked_cast(*this).supertypes_length());
}
if (instance_type == WASM_STRUCT_TYPE) { if (instance_type == WASM_STRUCT_TYPE) {
return WasmStruct::GcSafeSize(map); return WasmStruct::GcSafeSize(map);
} }
if (instance_type == WASM_ARRAY_TYPE) { if (instance_type == WASM_ARRAY_TYPE) {
return WasmArray::SizeFor(map, WasmArray::cast(*this).length()); return WasmArray::SizeFor(map, WasmArray::unchecked_cast(*this).length());
} }
#endif // V8_ENABLE_WEBASSEMBLY #endif // V8_ENABLE_WEBASSEMBLY
DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE); DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE);
......
...@@ -5703,24 +5703,23 @@ class LiftoffCompiler { ...@@ -5703,24 +5703,23 @@ class LiftoffCompiler {
constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged( constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged(
Map::kConstructorOrBackPointerOrNativeContextOffset); Map::kConstructorOrBackPointerOrNativeContextOffset);
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset, pinned); __ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset, pinned);
// Step 2: load the supertypes list into {tmp1}. // Step 2: check the list's length if needed.
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 needed.
uint32_t rtt_depth = uint32_t rtt_depth =
GetSubtypingDepth(decoder->module_, rtt.type.ref_index()); GetSubtypingDepth(decoder->module_, rtt.type.ref_index());
if (rtt_depth >= kMinimumSupertypeArraySize) { if (rtt_depth >= kMinimumSupertypeArraySize) {
LiftoffRegister list_length = tmp2; LiftoffRegister list_length = tmp2;
__ LoadFixedArrayLengthAsInt32(list_length, tmp1.gp(), pinned); int offset =
ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesLengthOffset);
__ LoadSmiAsInt32(list_length, tmp1.gp(), offset, pinned);
__ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(), __ emit_i32_cond_jumpi(kUnsignedLessEqual, no_match, list_length.gp(),
rtt_depth); rtt_depth);
} }
// Step 4: load the candidate list slot into {tmp1}, and compare it. // Step 3: load the candidate list slot into {tmp1}, and compare it.
__ LoadTaggedPointer( __ LoadTaggedPointer(
tmp1.gp(), tmp1.gp(), no_reg, tmp1.gp(), tmp1.gp(), no_reg,
wasm::ObjectAccess::ElementOffsetInTaggedFixedArray(rtt_depth), pinned); ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset +
rtt_depth * kTaggedSize),
pinned);
__ emit_cond_jump(kUnequal, no_match, rtt.type.kind(), tmp1.gp(), __ emit_cond_jump(kUnequal, no_match, rtt.type.kind(), tmp1.gp(),
rtt_reg.gp()); rtt_reg.gp());
......
...@@ -172,7 +172,6 @@ extern class AsmWasmData extends Struct { ...@@ -172,7 +172,6 @@ extern class AsmWasmData extends Struct {
} }
extern class WasmTypeInfo extends Foreign { extern class WasmTypeInfo extends Foreign {
supertypes: FixedArray;
// We must make sure that the StructType/ArrayType, which is allocated in // We must make sure that the StructType/ArrayType, which is allocated in
// the WasmModule's "signature_zone", stays around as long as there are // the WasmModule's "signature_zone", stays around as long as there are
// HeapObjects referring to it. Short term, we simply keep a reference to // HeapObjects referring to it. Short term, we simply keep a reference to
...@@ -182,6 +181,8 @@ extern class WasmTypeInfo extends Foreign { ...@@ -182,6 +181,8 @@ extern class WasmTypeInfo extends Foreign {
// and introduce a new link from here to just that zone using a Managed<...>. // and introduce a new link from here to just that zone using a Managed<...>.
// Details: https://bit.ly/2UxD4hW // Details: https://bit.ly/2UxD4hW
instance: WasmInstanceObject; instance: WasmInstanceObject;
const supertypes_length: Smi;
supertypes[supertypes_length]: Object;
} }
// WasmObject corresponds to data ref types which are WasmStruct and WasmArray. // WasmObject corresponds to data ref types which are WasmStruct and WasmArray.
......
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