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 {
const rttSupertypeLength: Smi =
%RawDownCast<WasmTypeInfo>(
rtt.constructor_or_back_pointer_or_native_context)
.supertypes.length;
.supertypes_length;
if (objectSupertypes.length <= rttSupertypeLength) {
return 0;
......
......@@ -101,21 +101,25 @@ Reduction WasmGCLowering::ReduceWasmTypeCheck(Node* node) {
gasm_.Int32Constant(1));
Node* type_info = gasm_.LoadWasmTypeInfo(map);
Node* supertypes = gasm_.LoadSupertypes(type_info);
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
// array length, we can access the supertype without bounds-checking the
// supertype array.
if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) {
Node* supertypes_length = gasm_.BuildChangeSmiToIntPtr(
gasm_.LoadFixedArrayLengthAsSmi(supertypes));
gasm_.GotoIfNot(gasm_.UintLessThan(rtt_depth_node, supertypes_length),
&end_label, BranchHint::kTrue, gasm_.Int32Constant(0));
Node* supertypes_length =
gasm_.BuildChangeSmiToIntPtr(gasm_.LoadImmutableFromObject(
MachineType::TaggedSigned(), type_info,
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(
supertypes, rtt_depth_node, MachineType::TaggedPointer());
Node* maybe_match = gasm_.LoadImmutableFromObject(
MachineType::TaggedPointer(), type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset +
kTaggedSize * rtt_depth));
gasm_.Goto(&end_label, gasm_.TaggedEqual(maybe_match, rtt));
......@@ -153,21 +157,25 @@ Reduction WasmGCLowering::ReduceWasmTypeCast(Node* node) {
gasm_.GotoIf(gasm_.TaggedEqual(map, rtt), &end_label, BranchHint::kTrue);
Node* type_info = gasm_.LoadWasmTypeInfo(map);
Node* supertypes = gasm_.LoadSupertypes(type_info);
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
// array length, we can access the supertype without bounds-checking the
// supertype array.
if (static_cast<uint32_t>(rtt_depth) >= wasm::kMinimumSupertypeArraySize) {
Node* supertypes_length = gasm_.BuildChangeSmiToIntPtr(
gasm_.LoadFixedArrayLengthAsSmi(supertypes));
gasm_.TrapUnless(gasm_.UintLessThan(rtt_depth_node, supertypes_length),
TrapId::kTrapIllegalCast);
Node* supertypes_length =
gasm_.BuildChangeSmiToIntPtr(gasm_.LoadImmutableFromObject(
MachineType::TaggedSigned(), type_info,
wasm::ObjectAccess::ToTagged(
WasmTypeInfo::kSupertypesLengthOffset)));
gasm_.TrapUnless(
gasm_.UintLessThan(gasm_.IntPtrConstant(rtt_depth), supertypes_length),
TrapId::kTrapIllegalCast);
}
Node* maybe_match = gasm_.LoadImmutableFixedArrayElement(
supertypes, rtt_depth_node, MachineType::TaggedPointer());
Node* maybe_match = gasm_.LoadImmutableFromObject(
MachineType::TaggedPointer(), type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset +
kTaggedSize * rtt_depth));
gasm_.TrapUnless(gasm_.TaggedEqual(maybe_match, rtt),
TrapId::kTrapIllegalCast);
......
......@@ -215,12 +215,6 @@ Node* WasmGraphAssembler::LoadWasmTypeInfo(Node* map) {
wasm::ObjectAccess::ToTagged(offset));
}
Node* WasmGraphAssembler::LoadSupertypes(Node* wasm_type_info) {
return LoadImmutableFromObject(
MachineType::TaggedPointer(), wasm_type_info,
wasm::ObjectAccess::ToTagged(WasmTypeInfo::kSupertypesOffset));
}
// FixedArrays.
Node* WasmGraphAssembler::LoadFixedArrayLengthAsSmi(Node* fixed_array) {
......
......@@ -170,8 +170,6 @@ class WasmGraphAssembler : public GraphAssembler {
Node* LoadWasmTypeInfo(Node* map);
Node* LoadSupertypes(Node* wasm_type_info);
// FixedArrays.
Node* LoadFixedArrayLengthAsSmi(Node* fixed_array);
......
......@@ -1829,7 +1829,11 @@ void AsmWasmData::AsmWasmDataPrint(std::ostream& os) {
void WasmTypeInfo::WasmTypeInfoPrint(std::ostream& os) {
PrintHeader(os, "WasmTypeInfo");
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";
}
......
......@@ -1547,37 +1547,38 @@ Handle<WasmTypeInfo> Factory::NewWasmTypeInfo(
// (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
// safe to do if the WTI is in old space.
// The supertypes list is constant after initialization, so we pretenure
// that too. The subtypes list, however, is expected to grow (and hence be
// replaced), so we don't pretenure it.
Handle<FixedArray> supertypes;
std::vector<Handle<Object>> supertypes;
if (opt_parent.is_null()) {
supertypes = NewFixedArray(wasm::kMinimumSupertypeArraySize);
for (int i = 0; i < supertypes->length(); i++) {
supertypes->set(i, *undefined_value());
}
supertypes.resize(wasm::kMinimumSupertypeArraySize, undefined_value());
} else {
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--;
Handle<WasmTypeInfo> parent_type_info =
handle(opt_parent->wasm_type_info(), isolate());
int first_undefined_index = -1;
for (int i = 0; i < parent_type_info->supertypes_length(); i++) {
Handle<Object> supertype =
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) {
supertypes = CopyArrayAndGrow(parent_supertypes, 1, AllocationType::kOld);
if (first_undefined_index >= 0) {
supertypes[first_undefined_index] = opt_parent;
} else {
supertypes = CopyFixedArray(parent_supertypes);
supertypes.emplace_back(opt_parent);
}
supertypes->set(last_defined_index + 1, *opt_parent);
}
Map map = *wasm_type_info_map();
WasmTypeInfo result = WasmTypeInfo::cast(AllocateRawWithImmortalMap(
map.instance_size(), AllocationType::kOld, map));
WasmTypeInfo::SizeFor(static_cast<int>(supertypes.size())),
AllocationType::kOld, map));
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.set_foreign_address(isolate(), type_address);
result.set_supertypes(*supertypes);
result.set_instance(*instance);
return handle(result, isolate());
}
......
......@@ -517,7 +517,7 @@ bool Heap::CreateInitialMaps() {
wasm_js_function_data)
IF_WASM(ALLOCATE_MAP, WASM_ON_FULFILLED_DATA_TYPE,
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)
ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
......
......@@ -713,11 +713,14 @@ class WasmTypeInfo::BodyDescriptor final : public BodyDescriptorBase {
ObjectVisitor* v) {
Foreign::BodyDescriptor::IterateBody<ObjectVisitor>(map, obj, object_size,
v);
IteratePointer(obj, kSupertypesOffset, 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 {
......
......@@ -2288,11 +2288,15 @@ int HeapObject::SizeFromMap(Map map) const {
CoverageInfo::unchecked_cast(*this).slot_count());
}
#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) {
return WasmStruct::GcSafeSize(map);
}
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
DCHECK_EQ(instance_type, EMBEDDER_DATA_ARRAY_TYPE);
......
......@@ -5703,24 +5703,23 @@ class LiftoffCompiler {
constexpr int kTypeInfoOffset = wasm::ObjectAccess::ToTagged(
Map::kConstructorOrBackPointerOrNativeContextOffset);
__ LoadTaggedPointer(tmp1.gp(), tmp1.gp(), no_reg, kTypeInfoOffset, pinned);
// 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 needed.
// Step 2: check the list's length if needed.
uint32_t rtt_depth =
GetSubtypingDepth(decoder->module_, rtt.type.ref_index());
if (rtt_depth >= kMinimumSupertypeArraySize) {
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(),
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(
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(),
rtt_reg.gp());
......
......@@ -172,7 +172,6 @@ extern class AsmWasmData extends Struct {
}
extern class WasmTypeInfo extends Foreign {
supertypes: FixedArray;
// We must make sure that the StructType/ArrayType, which is allocated in
// the WasmModule's "signature_zone", stays around as long as there are
// HeapObjects referring to it. Short term, we simply keep a reference to
......@@ -182,6 +181,8 @@ extern class WasmTypeInfo extends Foreign {
// and introduce a new link from here to just that zone using a Managed<...>.
// Details: https://bit.ly/2UxD4hW
instance: WasmInstanceObject;
const supertypes_length: Smi;
supertypes[supertypes_length]: Object;
}
// 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