Revert "Reland "[vm] Unify hash codes in type objects""

This reverts commit f96d179ae4.

Reason for revert: failures on Flutter Windows bots (https://github.com/flutter/flutter/issues/127666)

Original change's description:
> Reland "[vm] Unify hash codes in type objects"
>
> This is a reland of commit e82a2230fd
>
> Original change's description:
> > [vm] Unify hash codes in type objects
> >
> > TEST=ci
> >
> > Change-Id: I53d2268c3aab6fc4583c3201051b68f8fc05d56d
> > Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/305361
> > Commit-Queue: Alexander Markov <alexmarkov@google.com>
> > Reviewed-by: Ryan Macnak <rmacnak@google.com>
>
> TEST=ci
> Change-Id: I333ed4297ad4af97000c98dfe4547b4cab6cb313
> Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/305780
> Reviewed-by: Ryan Macnak <rmacnak@google.com>
> Commit-Queue: Alexander Markov <alexmarkov@google.com>

Change-Id: I1a933e39b81e99e732db56e616b24d6ec604f01b
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/306000
Auto-Submit: Alexander Markov <alexmarkov@google.com>
Bot-Commit: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
Commit-Queue: Rubber Stamper <rubber-stamper@appspot.gserviceaccount.com>
This commit is contained in:
Alexander Markov 2023-05-26 14:36:14 +00:00 committed by Commit Queue
parent e213846ba0
commit c57f889d43
16 changed files with 409 additions and 227 deletions

View file

@ -257,6 +257,14 @@ DEFINE_NATIVE_ENTRY(AbstractType_equality, 0, 2) {
return Bool::Get(type.IsEquivalent(other, TypeEquality::kSyntactical)).ptr();
}
DEFINE_NATIVE_ENTRY(Type_getHashCode, 0, 1) {
const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0));
intptr_t hash_val = type.Hash();
ASSERT(hash_val > 0);
ASSERT(Smi::IsValid(hash_val));
return Smi::New(hash_val);
}
DEFINE_NATIVE_ENTRY(Type_equality, 0, 2) {
const Type& type = Type::CheckedHandle(zone, arguments->NativeArgAt(0));
const Instance& other =

View file

@ -30,6 +30,7 @@ namespace dart {
V(AbstractType_getHashCode, 1) \
V(AbstractType_toString, 1) \
V(Type_equality, 2) \
V(Type_getHashCode, 1) \
V(LibraryPrefix_isLoaded, 1) \
V(LibraryPrefix_setLoaded, 1) \
V(LibraryPrefix_loadingUnit, 1) \

View file

@ -1076,7 +1076,10 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
//
// Caching of the canonical hash codes happens for:
//
// * UntaggedAbstractType::hash_
// * UntaggedType::hash_
// * UntaggedFunctionType::hash_
// * UntaggedRecordType::hash_
// * UntaggedTypeParameter::hash_
// * UntaggedTypeArguments::hash_
// * InstancePtr (weak table)
// * ArrayPtr (weak table)
@ -1093,14 +1096,25 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
class ClearTypeHashVisitor : public ObjectVisitor {
public:
explicit ClearTypeHashVisitor(Zone* zone)
: type_(AbstractType::Handle(zone)),
: type_param_(TypeParameter::Handle(zone)),
type_(Type::Handle(zone)),
function_type_(FunctionType::Handle(zone)),
record_type_(RecordType::Handle(zone)),
type_args_(TypeArguments::Handle(zone)) {}
void VisitObject(ObjectPtr obj) override {
if (obj->IsType() || obj->IsTypeParameter() || obj->IsFunctionType() ||
obj->IsRecordType()) {
if (obj->IsTypeParameter()) {
type_param_ ^= obj;
type_param_.SetHash(0);
} else if (obj->IsType()) {
type_ ^= obj;
type_.SetHash(0);
} else if (obj->IsFunctionType()) {
function_type_ ^= obj;
function_type_.SetHash(0);
} else if (obj->IsRecordType()) {
record_type_ ^= obj;
record_type_.SetHash(0);
} else if (obj->IsTypeArguments()) {
type_args_ ^= obj;
type_args_.SetHash(0);
@ -1108,7 +1122,10 @@ class ClearTypeHashVisitor : public ObjectVisitor {
}
private:
AbstractType& type_;
TypeParameter& type_param_;
Type& type_;
FunctionType& function_type_;
RecordType& record_type_;
TypeArguments& type_args_;
};

View file

@ -1199,6 +1199,15 @@ void AsmIntrinsifier::String_getHashCode(Assembler* assembler,
__ Bind(normal_ir_body); // Hash not yet computed.
}
void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
__ ldr(R0, FieldAddress(R0, target::Type::hash_offset()));
__ cmp(R0, Operand(0));
READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
__ Bind(normal_ir_body); // Hash not yet computed.
}
void AsmIntrinsifier::Type_equality(Assembler* assembler,
Label* normal_ir_body) {
Label equal, not_equal, equiv_cids_may_be_generic, equiv_cids, check_legacy;
@ -1262,7 +1271,7 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
__ ldr(R0, FieldAddress(R0, target::AbstractType::hash_offset()));
__ ldr(R0, FieldAddress(R0, target::FunctionType::hash_offset()));
__ cmp(R0, Operand(0));
READS_RETURN_ADDRESS_FROM_LR(__ bx(LR, NE));
__ Bind(normal_ir_body); // Hash not yet computed.

View file

@ -1359,6 +1359,16 @@ void AsmIntrinsifier::String_getHashCode(Assembler* assembler,
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
__ LoadCompressedSmi(R0, FieldAddress(R0, target::Type::hash_offset()));
__ cbz(normal_ir_body, R0, kObjectBytes);
__ ret();
// Hash not yet computed.
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::Type_equality(Assembler* assembler,
Label* normal_ir_body) {
Label equal, not_equal, equiv_cids_may_be_generic, equiv_cids, check_legacy;
@ -1423,7 +1433,7 @@ void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ ldr(R0, Address(SP, 0 * target::kWordSize));
__ LoadCompressedSmi(R0,
FieldAddress(R0, target::AbstractType::hash_offset()));
FieldAddress(R0, target::FunctionType::hash_offset()));
__ cbz(normal_ir_body, R0, kObjectBytes);
__ ret();
// Hash not yet computed.

View file

@ -1342,6 +1342,17 @@ void AsmIntrinsifier::String_getHashCode(Assembler* assembler,
// Hash not yet computed.
}
void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ movl(EAX, Address(ESP, +1 * target::kWordSize)); // Type object.
__ movl(EAX, FieldAddress(EAX, target::Type::hash_offset()));
__ testl(EAX, EAX);
__ j(EQUAL, normal_ir_body, Assembler::kNearJump);
__ ret();
__ Bind(normal_ir_body);
// Hash not yet computed.
}
void AsmIntrinsifier::Type_equality(Assembler* assembler,
Label* normal_ir_body) {
Label equal, not_equal, equiv_cids_may_be_generic, equiv_cids, check_legacy;
@ -1405,8 +1416,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ movl(EAX, Address(ESP, +1 * target::kWordSize)); // AbstractType object.
__ movl(EAX, FieldAddress(EAX, target::AbstractType::hash_offset()));
__ movl(EAX, Address(ESP, +1 * target::kWordSize)); // FunctionType object.
__ movl(EAX, FieldAddress(EAX, target::FunctionType::hash_offset()));
__ testl(EAX, EAX);
__ j(EQUAL, normal_ir_body, Assembler::kNearJump);
__ ret();

View file

@ -1396,6 +1396,16 @@ void AsmIntrinsifier::String_getHashCode(Assembler* assembler,
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ lx(A0, Address(SP, 0 * target::kWordSize));
__ LoadCompressed(A0, FieldAddress(A0, target::Type::hash_offset()));
__ beqz(A0, normal_ir_body, Assembler::kNearJump);
__ ret();
// Hash not yet computed.
__ Bind(normal_ir_body);
}
void AsmIntrinsifier::Type_equality(Assembler* assembler,
Label* normal_ir_body) {
Label equal, not_equal, equiv_cids_may_be_generic, equiv_cids, check_legacy;
@ -1458,7 +1468,7 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ lx(A0, Address(SP, 0 * target::kWordSize));
__ LoadCompressed(A0, FieldAddress(A0, target::AbstractType::hash_offset()));
__ LoadCompressed(A0, FieldAddress(A0, target::FunctionType::hash_offset()));
__ beqz(A0, normal_ir_body, Assembler::kNearJump);
__ ret();
// Hash not yet computed.

View file

@ -1248,6 +1248,19 @@ void AsmIntrinsifier::String_getHashCode(Assembler* assembler,
// Hash not yet computed.
}
void AsmIntrinsifier::Type_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ movq(RAX, Address(RSP, +1 * target::kWordSize)); // Type object.
__ LoadCompressedSmi(RAX, FieldAddress(RAX, target::Type::hash_offset()));
ASSERT(kSmiTag == 0);
ASSERT(kSmiTagShift == 1);
__ OBJ(test)(RAX, RAX);
__ j(ZERO, normal_ir_body, Assembler::kNearJump);
__ ret();
__ Bind(normal_ir_body);
// Hash not yet computed.
}
void AsmIntrinsifier::Type_equality(Assembler* assembler,
Label* normal_ir_body) {
Label equal, not_equal, equiv_cids_may_be_generic, equiv_cids, check_legacy;
@ -1311,9 +1324,9 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
void AsmIntrinsifier::AbstractType_getHashCode(Assembler* assembler,
Label* normal_ir_body) {
__ movq(RAX, Address(RSP, +1 * target::kWordSize)); // AbstractType object.
__ movq(RAX, Address(RSP, +1 * target::kWordSize)); // FunctionType object.
__ LoadCompressedSmi(RAX,
FieldAddress(RAX, target::AbstractType::hash_offset()));
FieldAddress(RAX, target::FunctionType::hash_offset()));
ASSERT(kSmiTag == 0);
ASSERT(kSmiTagShift == 1);
__ OBJ(test)(RAX, RAX);

View file

@ -374,6 +374,7 @@ namespace dart {
V(_TwoByteString, ==, TwoByteString_equality, 0x4ea9ddc9) \
V(_AbstractType, get:hashCode, AbstractType_getHashCode, 0x75e0d454) \
V(_AbstractType, ==, AbstractType_equality, 0x465868ae) \
V(_Type, get:hashCode, Type_getHashCode, 0x75e0d454) \
V(_Type, ==, Type_equality, 0x465868ae) \
V(::, _getHash, Object_getHash, 0xc60ff758) \

View file

@ -717,7 +717,6 @@ class Pointer : public AllStatic {
class AbstractType : public AllStatic {
public:
static word flags_offset();
static word hash_offset();
static word type_test_stub_entry_point_offset();
static word InstanceSize();
FINAL_CLASS();
@ -725,6 +724,7 @@ class AbstractType : public AllStatic {
class Type : public AllStatic {
public:
static word hash_offset();
static word arguments_offset();
static word InstanceSize();
FINAL_CLASS();
@ -732,6 +732,7 @@ class Type : public AllStatic {
class FunctionType : public AllStatic {
public:
static word hash_offset();
static word packed_parameter_counts_offset();
static word packed_type_parameter_counts_offset();
static word named_parameter_names_offset();

File diff suppressed because it is too large Load diff

View file

@ -103,7 +103,6 @@
CONSTANT(SubtypeTestCache, kTestResult) \
CONSTANT(TypeArguments, kMaxElements) \
FIELD(AbstractType, flags_offset) \
FIELD(AbstractType, hash_offset) \
FIELD(AbstractType, type_test_stub_entry_point_offset) \
FIELD(ArgumentsDescriptor, count_offset) \
FIELD(ArgumentsDescriptor, size_offset) \
@ -354,6 +353,7 @@
FIELD(TimelineStream, enabled_offset) \
FIELD(TwoByteString, data_offset) \
FIELD(Type, arguments_offset) \
FIELD(Type, hash_offset) \
FIELD(Finalizer, type_arguments_offset) \
FIELD(Finalizer, callback_offset) \
FIELD(FinalizerBase, all_entries_offset) \
@ -367,6 +367,7 @@
FIELD(FinalizerEntry, token_offset) \
FIELD(FinalizerEntry, value_offset) \
FIELD(NativeFinalizer, callback_offset) \
FIELD(FunctionType, hash_offset) \
FIELD(FunctionType, named_parameter_names_offset) \
FIELD(FunctionType, packed_parameter_counts_offset) \
FIELD(FunctionType, packed_type_parameter_counts_offset) \

View file

@ -21601,7 +21601,10 @@ bool AbstractType::IsSubtypeOfFutureOr(
return false;
}
uword AbstractType::ComputeHash() const {
uword AbstractType::Hash() const {
// All subclasses should implement this appropriately, so the only value that
// should reach this implementation should be the null value.
ASSERT(IsNull());
// AbstractType is an abstract class.
UNREACHABLE();
return 0;

View file

@ -8528,9 +8528,6 @@ class AbstractType : public Instance {
static intptr_t flags_offset() {
return OFFSET_OF(UntaggedAbstractType, flags_);
}
static intptr_t hash_offset() {
return OFFSET_OF(UntaggedAbstractType, hash_);
}
bool IsFinalized() const {
const auto state = type_state();
@ -8666,8 +8663,7 @@ class AbstractType : public Instance {
// list and mark ambiguous triplets to be printed.
virtual void EnumerateURIs(URIs* uris) const;
uword Hash() const;
virtual uword ComputeHash() const;
virtual uword Hash() const;
// The name of this type's class, i.e. without the type argument names of this
// type.
@ -8841,8 +8837,6 @@ class AbstractType : public Instance {
const AbstractType& other_type,
TypeEquality kind) const;
void SetHash(intptr_t value) const;
UntaggedAbstractType::TypeState type_state() const {
return static_cast<UntaggedAbstractType::TypeState>(
UntaggedAbstractType::TypeStateBits::decode(untag()->flags()));
@ -8853,7 +8847,6 @@ class AbstractType : public Instance {
HEAP_OBJECT_IMPLEMENTATION(AbstractType, Instance);
friend class Class;
friend class ClearTypeHashVisitor;
friend class Function;
friend class TypeArguments;
};
@ -8865,6 +8858,7 @@ class Type : public AbstractType {
static intptr_t arguments_offset() {
return OFFSET_OF(UntaggedType, arguments_);
}
static intptr_t hash_offset() { return OFFSET_OF(UntaggedType, hash_); }
virtual bool HasTypeClass() const {
ASSERT(type_class_id() != kIllegalCid);
return true;
@ -8917,7 +8911,8 @@ class Type : public AbstractType {
virtual void PrintName(NameVisibility visibility,
BaseTextBuffer* printer) const;
virtual uword ComputeHash() const;
virtual uword Hash() const;
uword ComputeHash() const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(UntaggedType));
@ -8992,6 +8987,8 @@ class Type : public AbstractType {
Heap::Space space = Heap::kOld);
private:
void SetHash(intptr_t value) const;
// Takes an intptr_t since the cids of some classes are larger than will fit
// in ClassIdTagType. This allows us to guard against that case, instead of
// silently truncating the cid.
@ -9002,6 +8999,7 @@ class Type : public AbstractType {
FINAL_HEAP_OBJECT_IMPLEMENTATION(Type, AbstractType);
friend class Class;
friend class TypeArguments;
friend class ClearTypeHashVisitor;
};
// A FunctionType represents the type of a function. It describes most of the
@ -9022,6 +9020,9 @@ class FunctionType : public AbstractType {
using PackedNumOptionalParameters =
UntaggedFunctionType::PackedNumOptionalParameters;
static intptr_t hash_offset() {
return OFFSET_OF(UntaggedFunctionType, hash_);
}
virtual bool HasTypeClass() const { return false; }
FunctionTypePtr ToNullability(Nullability value, Heap::Space space) const;
virtual classid_t type_class_id() const { return kIllegalCid; }
@ -9057,7 +9058,8 @@ class FunctionType : public AbstractType {
virtual void PrintName(NameVisibility visibility,
BaseTextBuffer* printer) const;
virtual uword ComputeHash() const;
virtual uword Hash() const;
uword ComputeHash() const;
bool IsSubtypeOf(
const FunctionType& other,
@ -9286,10 +9288,13 @@ class FunctionType : public AbstractType {
static FunctionTypePtr Clone(const FunctionType& orig, Heap::Space space);
private:
void SetHash(intptr_t value) const;
static FunctionTypePtr New(Heap::Space space);
FINAL_HEAP_OBJECT_IMPLEMENTATION(FunctionType, AbstractType);
friend class Class;
friend class ClearTypeHashVisitor;
friend class Function;
};
@ -9363,6 +9368,8 @@ class TypeParameter : public AbstractType {
virtual void PrintName(NameVisibility visibility,
BaseTextBuffer* printer) const;
virtual uword Hash() const;
// Returns type corresponding to [this] type parameter from the
// given [instantiator_type_arguments] and [function_type_arguments].
// Unlike InstantiateFrom, nullability of type parameter is not applied to
@ -9391,7 +9398,8 @@ class TypeParameter : public AbstractType {
Nullability nullability);
private:
virtual uword ComputeHash() const;
uword ComputeHash() const;
void SetHash(intptr_t value) const;
void set_owner(const Object& value) const;
@ -9399,6 +9407,7 @@ class TypeParameter : public AbstractType {
FINAL_HEAP_OBJECT_IMPLEMENTATION(TypeParameter, AbstractType);
friend class Class;
friend class ClearTypeHashVisitor;
};
class Number : public Instance {
@ -11037,6 +11046,7 @@ class RecordShape {
// names of the named fields.
class RecordType : public AbstractType {
public:
static intptr_t hash_offset() { return OFFSET_OF(UntaggedRecordType, hash_); }
virtual bool HasTypeClass() const { return false; }
RecordTypePtr ToNullability(Nullability value, Heap::Space space) const;
virtual classid_t type_class_id() const { return kIllegalCid; }
@ -11072,7 +11082,8 @@ class RecordType : public AbstractType {
virtual void PrintName(NameVisibility visibility,
BaseTextBuffer* printer) const;
virtual uword ComputeHash() const;
virtual uword Hash() const;
uword ComputeHash() const;
bool IsSubtypeOf(
const RecordType& other,
@ -11103,6 +11114,8 @@ class RecordType : public AbstractType {
Heap::Space space = Heap::kOld);
private:
void SetHash(intptr_t value) const;
void set_shape(RecordShape shape) const;
void set_field_types(const Array& value) const;
@ -11111,6 +11124,7 @@ class RecordType : public AbstractType {
FINAL_HEAP_OBJECT_IMPLEMENTATION(RecordType, AbstractType);
friend class Class;
friend class ClassFinalizer;
friend class ClearTypeHashVisitor;
friend class Record;
};
@ -13039,7 +13053,7 @@ ObjectPtr MegamorphicCache::GetTargetFunction(const Array& array,
return array.At((index * kEntryLength) + kTargetFunctionIndex);
}
inline uword AbstractType::Hash() const {
inline uword Type::Hash() const {
ASSERT(IsFinalized());
intptr_t result = Smi::Value(untag()->hash());
if (result != 0) {
@ -13048,7 +13062,37 @@ inline uword AbstractType::Hash() const {
return ComputeHash();
}
inline void AbstractType::SetHash(intptr_t value) const {
inline void Type::SetHash(intptr_t value) const {
// This is only safe because we create a new Smi, which does not cause
// heap allocation.
untag()->set_hash(Smi::New(value));
}
inline uword FunctionType::Hash() const {
ASSERT(IsFinalized());
intptr_t result = Smi::Value(untag()->hash());
if (result != 0) {
return result;
}
return ComputeHash();
}
inline void FunctionType::SetHash(intptr_t value) const {
// This is only safe because we create a new Smi, which does not cause
// heap allocation.
untag()->set_hash(Smi::New(value));
}
inline uword RecordType::Hash() const {
ASSERT(IsFinalized());
intptr_t result = Smi::Value(untag()->hash());
if (result != 0) {
return result;
}
return ComputeHash();
}
inline void RecordType::SetHash(intptr_t value) const {
// This is only safe because we create a new Smi, which does not cause
// heap allocation.
untag()->set_hash(Smi::New(value));
@ -13058,6 +13102,21 @@ inline intptr_t RecordType::NumFields() const {
return Array::LengthOf(field_types());
}
inline uword TypeParameter::Hash() const {
ASSERT(IsFinalized());
intptr_t result = Smi::Value(untag()->hash());
if (result != 0) {
return result;
}
return ComputeHash();
}
inline void TypeParameter::SetHash(intptr_t value) const {
// This is only safe because we create a new Smi, which does not cause
// heap allocation.
untag()->set_hash(Smi::New(value));
}
inline uword TypeArguments::Hash() const {
if (IsNull()) return kAllDynamicHash;
intptr_t result = Smi::Value(untag()->hash());

View file

@ -2643,7 +2643,6 @@ class UntaggedAbstractType : public UntaggedInstance {
// Accessed from generated code.
std::atomic<uint32_t> flags_;
COMPRESSED_POINTER_FIELD(CodePtr, type_test_stub)
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
VISIT_FROM(type_test_stub)
uint32_t flags() const { return flags_.load(std::memory_order_relaxed); }
@ -2683,7 +2682,8 @@ class UntaggedType : public UntaggedAbstractType {
RAW_HEAP_OBJECT_IMPLEMENTATION(Type);
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, arguments)
VISIT_TO(arguments)
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
VISIT_TO(hash)
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
@ -2707,7 +2707,8 @@ class UntaggedFunctionType : public UntaggedAbstractType {
COMPRESSED_POINTER_FIELD(AbstractTypePtr, result_type)
COMPRESSED_POINTER_FIELD(ArrayPtr, parameter_types)
COMPRESSED_POINTER_FIELD(ArrayPtr, named_parameter_names);
VISIT_TO(named_parameter_names)
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
VISIT_TO(hash)
AtomicBitFieldContainer<uint32_t> packed_parameter_counts_;
AtomicBitFieldContainer<uint16_t> packed_type_parameter_counts_;
@ -2757,7 +2758,8 @@ class UntaggedRecordType : public UntaggedAbstractType {
COMPRESSED_SMI_FIELD(SmiPtr, shape)
COMPRESSED_POINTER_FIELD(ArrayPtr, field_types)
VISIT_TO(field_types)
COMPRESSED_SMI_FIELD(SmiPtr, hash)
VISIT_TO(hash)
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
};
@ -2772,6 +2774,7 @@ class UntaggedTypeParameter : public UntaggedAbstractType {
private:
RAW_HEAP_OBJECT_IMPLEMENTATION(TypeParameter);
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
// FunctionType or Smi (class id).
COMPRESSED_POINTER_FIELD(ObjectPtr, owner)
VISIT_TO(owner)

View file

@ -27,6 +27,11 @@ class _Type extends _AbstractType {
throw "Unreachable";
}
@pragma("vm:recognized", "asm-intrinsic")
@pragma("vm:exact-result-type", "dart:core#_Smi")
@pragma("vm:external-name", "Type_getHashCode")
external int get hashCode;
@pragma("vm:recognized", "asm-intrinsic")
@pragma("vm:exact-result-type", bool)
@pragma("vm:external-name", "Type_equality")