mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
[vm] Unify nullability and type state among all types
This change moves 'nullability' and 'type_state' from all kinds of types to AbstractType base class. This removes a lot of code duplication and allows uniform access to nullability and type state for all kinds of types. TEST=ci Fixes https://github.com/dart-lang/sdk/issues/47034 Change-Id: I1f0dc7fda78426db83fec6a20ebebcd632ad6d99 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/260662 Reviewed-by: Tess Strickland <sstrickl@google.com> Commit-Queue: Alexander Markov <alexmarkov@google.com> Reviewed-by: Ryan Macnak <rmacnak@google.com>
This commit is contained in:
parent
f04984b432
commit
d592882f49
|
@ -4046,10 +4046,6 @@ class LibraryPrefixDeserializationCluster : public DeserializationCluster {
|
|||
}
|
||||
};
|
||||
|
||||
// Used to pack nullability into other serialized values.
|
||||
static constexpr intptr_t kNullabilityBitSize = 2;
|
||||
static constexpr intptr_t kNullabilityBitMask = (1 << kNullabilityBitSize) - 1;
|
||||
|
||||
#if !defined(DART_PRECOMPILED_RUNTIME)
|
||||
class TypeSerializationCluster
|
||||
: public CanonicalSetSerializationCluster<
|
||||
|
@ -4073,9 +4069,9 @@ class TypeSerializationCluster
|
|||
|
||||
PushFromTo(type);
|
||||
|
||||
ASSERT(type->untag()->type_class_id_ != kIllegalCid);
|
||||
ASSERT(type->untag()->type_class_id() != kIllegalCid);
|
||||
ClassPtr type_class =
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id_);
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id());
|
||||
s->Push(type_class);
|
||||
}
|
||||
|
||||
|
@ -4108,7 +4104,7 @@ class TypeSerializationCluster
|
|||
// Keep in sync with Type::Canonicalize.
|
||||
virtual bool IsInCanonicalSet(Serializer* s, TypePtr type) {
|
||||
ClassPtr type_class =
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id_);
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id());
|
||||
if (type_class->untag()->declaration_type() != type) {
|
||||
return true;
|
||||
}
|
||||
|
@ -4123,25 +4119,12 @@ class TypeSerializationCluster
|
|||
#if defined(DART_PRECOMPILER)
|
||||
if (FLAG_write_v8_snapshot_profile_to != nullptr) {
|
||||
ClassPtr type_class =
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id_);
|
||||
s->isolate_group()->class_table()->At(type->untag()->type_class_id());
|
||||
s->AttributePropertyRef(type_class, "<type_class>");
|
||||
}
|
||||
#endif
|
||||
WriteFromTo(type);
|
||||
COMPILE_ASSERT(
|
||||
std::is_unsigned<decltype(UntaggedType::type_class_id_)>::value);
|
||||
s->WriteUnsigned(type->untag()->type_class_id_);
|
||||
ASSERT(type->untag()->type_state_ < (1 << UntaggedType::kTypeStateBitSize));
|
||||
ASSERT(type->untag()->nullability_ < (1 << kNullabilityBitSize));
|
||||
static_assert(UntaggedType::kTypeStateBitSize + kNullabilityBitSize <=
|
||||
kBitsPerByte * sizeof(uint8_t),
|
||||
"Cannot pack type_state_ and nullability_ into a uint8_t");
|
||||
const uint8_t combined =
|
||||
(type->untag()->type_state_ << kNullabilityBitSize) |
|
||||
type->untag()->nullability_;
|
||||
ASSERT_EQUAL(type->untag()->type_state_, combined >> kNullabilityBitSize);
|
||||
ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
|
||||
s->Write<uint8_t>(combined);
|
||||
s->WriteUnsigned(type->untag()->flags_);
|
||||
}
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
@ -4170,12 +4153,7 @@ class TypeDeserializationCluster
|
|||
Deserializer::InitializeHeader(type, kTypeCid, Type::InstanceSize(),
|
||||
mark_canonical);
|
||||
d.ReadFromTo(type);
|
||||
COMPILE_ASSERT(
|
||||
std::is_unsigned<decltype(UntaggedType::type_class_id_)>::value);
|
||||
type->untag()->type_class_id_ = d.ReadUnsigned();
|
||||
const uint8_t combined = d.Read<uint8_t>();
|
||||
type->untag()->type_state_ = combined >> kNullabilityBitSize;
|
||||
type->untag()->nullability_ = combined & kNullabilityBitMask;
|
||||
type->untag()->flags_ = d.ReadUnsigned();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4257,19 +4235,8 @@ class FunctionTypeSerializationCluster
|
|||
void WriteFunctionType(Serializer* s, FunctionTypePtr type) {
|
||||
AutoTraceObject(type);
|
||||
WriteFromTo(type);
|
||||
ASSERT(type->untag()->type_state_ <
|
||||
(1 << UntaggedFunctionType::kTypeStateBitSize));
|
||||
ASSERT(type->untag()->nullability_ < (1 << kNullabilityBitSize));
|
||||
static_assert(
|
||||
UntaggedFunctionType::kTypeStateBitSize + kNullabilityBitSize <=
|
||||
kBitsPerByte * sizeof(uint8_t),
|
||||
"Cannot pack type_state_ and nullability_ into a uint8_t");
|
||||
const uint8_t combined =
|
||||
(type->untag()->type_state_ << kNullabilityBitSize) |
|
||||
type->untag()->nullability_;
|
||||
ASSERT_EQUAL(type->untag()->type_state_, combined >> kNullabilityBitSize);
|
||||
ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
|
||||
s->Write<uint8_t>(combined);
|
||||
ASSERT(Utils::IsUint(8, type->untag()->flags_));
|
||||
s->Write<uint8_t>(type->untag()->flags_);
|
||||
s->Write<uint32_t>(type->untag()->packed_parameter_counts_);
|
||||
s->Write<uint16_t>(type->untag()->packed_type_parameter_counts_);
|
||||
}
|
||||
|
@ -4300,9 +4267,7 @@ class FunctionTypeDeserializationCluster
|
|||
Deserializer::InitializeHeader(
|
||||
type, kFunctionTypeCid, FunctionType::InstanceSize(), mark_canonical);
|
||||
d.ReadFromTo(type);
|
||||
const uint8_t combined = d.Read<uint8_t>();
|
||||
type->untag()->type_state_ = combined >> kNullabilityBitSize;
|
||||
type->untag()->nullability_ = combined & kNullabilityBitMask;
|
||||
type->untag()->flags_ = d.Read<uint8_t>();
|
||||
type->untag()->packed_parameter_counts_ = d.Read<uint32_t>();
|
||||
type->untag()->packed_type_parameter_counts_ = d.Read<uint16_t>();
|
||||
}
|
||||
|
@ -4386,18 +4351,8 @@ class RecordTypeSerializationCluster
|
|||
void WriteRecordType(Serializer* s, RecordTypePtr type) {
|
||||
AutoTraceObject(type);
|
||||
WriteFromTo(type);
|
||||
ASSERT(type->untag()->type_state_ <
|
||||
(1 << UntaggedRecordType::kTypeStateBitSize));
|
||||
ASSERT(type->untag()->nullability_ < (1 << kNullabilityBitSize));
|
||||
static_assert(UntaggedRecordType::kTypeStateBitSize + kNullabilityBitSize <=
|
||||
kBitsPerByte * sizeof(uint8_t),
|
||||
"Cannot pack type_state_ and nullability_ into a uint8_t");
|
||||
const uint8_t combined =
|
||||
(type->untag()->type_state_ << kNullabilityBitSize) |
|
||||
type->untag()->nullability_;
|
||||
ASSERT_EQUAL(type->untag()->type_state_, combined >> kNullabilityBitSize);
|
||||
ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
|
||||
s->Write<uint8_t>(combined);
|
||||
ASSERT(Utils::IsUint(8, type->untag()->flags_));
|
||||
s->Write<uint8_t>(type->untag()->flags_);
|
||||
}
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
@ -4425,9 +4380,7 @@ class RecordTypeDeserializationCluster
|
|||
Deserializer::InitializeHeader(
|
||||
type, kRecordTypeCid, RecordType::InstanceSize(), mark_canonical);
|
||||
d.ReadFromTo(type);
|
||||
const uint8_t combined = d.Read<uint8_t>();
|
||||
type->untag()->type_state_ = combined >> kNullabilityBitSize;
|
||||
type->untag()->nullability_ = combined & kNullabilityBitMask;
|
||||
type->untag()->flags_ = d.Read<uint8_t>();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4534,16 +4487,20 @@ class TypeRefDeserializationCluster : public DeserializationCluster {
|
|||
}
|
||||
|
||||
TypeRef& type_ref = TypeRef::Handle(d->zone());
|
||||
AbstractType& type = AbstractType::Handle(d->zone());
|
||||
Code& stub = Code::Handle(d->zone());
|
||||
const bool includes_code = Snapshot::IncludesCode(d->kind());
|
||||
|
||||
if (Snapshot::IncludesCode(d->kind())) {
|
||||
for (intptr_t id = start_index_, n = stop_index_; id < n; id++) {
|
||||
type_ref ^= refs.At(id);
|
||||
for (intptr_t id = start_index_, n = stop_index_; id < n; id++) {
|
||||
type_ref ^= refs.At(id);
|
||||
|
||||
// Refresh finalization state and nullability.
|
||||
type = type_ref.type();
|
||||
type_ref.set_type(type);
|
||||
|
||||
if (includes_code) {
|
||||
type_ref.UpdateTypeTestingStubEntryPoint();
|
||||
}
|
||||
} else {
|
||||
for (intptr_t id = start_index_, n = stop_index_; id < n; id++) {
|
||||
type_ref ^= refs.At(id);
|
||||
} else {
|
||||
stub = TypeTestingStubGenerator::DefaultCodeForType(type_ref);
|
||||
type_ref.InitializeTypeTestingStubNonAtomic(stub);
|
||||
}
|
||||
|
@ -4599,16 +4556,8 @@ class TypeParameterSerializationCluster
|
|||
s->Write<int32_t>(type->untag()->parameterized_class_id_);
|
||||
s->Write<uint8_t>(type->untag()->base_);
|
||||
s->Write<uint8_t>(type->untag()->index_);
|
||||
ASSERT(type->untag()->flags_ < (1 << UntaggedTypeParameter::kFlagsBitSize));
|
||||
ASSERT(type->untag()->nullability_ < (1 << kNullabilityBitSize));
|
||||
static_assert(UntaggedTypeParameter::kFlagsBitSize + kNullabilityBitSize <=
|
||||
kBitsPerByte * sizeof(uint8_t),
|
||||
"Cannot pack flags_ and nullability_ into a uint8_t");
|
||||
const uint8_t combined = (type->untag()->flags_ << kNullabilityBitSize) |
|
||||
type->untag()->nullability_;
|
||||
ASSERT_EQUAL(type->untag()->flags_, combined >> kNullabilityBitSize);
|
||||
ASSERT_EQUAL(type->untag()->nullability_, combined & kNullabilityBitMask);
|
||||
s->Write<uint8_t>(combined);
|
||||
ASSERT(Utils::IsUint(8, type->untag()->flags_));
|
||||
s->Write<uint8_t>(type->untag()->flags_);
|
||||
}
|
||||
};
|
||||
#endif // !DART_PRECOMPILED_RUNTIME
|
||||
|
@ -4641,9 +4590,7 @@ class TypeParameterDeserializationCluster
|
|||
type->untag()->parameterized_class_id_ = d.Read<int32_t>();
|
||||
type->untag()->base_ = d.Read<uint8_t>();
|
||||
type->untag()->index_ = d.Read<uint8_t>();
|
||||
const uint8_t combined = d.Read<uint8_t>();
|
||||
type->untag()->flags_ = combined >> kNullabilityBitSize;
|
||||
type->untag()->nullability_ = combined & kNullabilityBitMask;
|
||||
type->untag()->flags_ = d.Read<uint8_t>();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -659,6 +659,11 @@ void ClassFinalizer::FillAndFinalizeTypeArguments(
|
|||
AbstractType& unfinalized_type = AbstractType::Handle(zone);
|
||||
if (super_type_arg.IsTypeRef()) {
|
||||
unfinalized_type = TypeRef::Cast(super_type_arg).type();
|
||||
if (unfinalized_type.IsFinalized()) {
|
||||
super_type_arg.SetIsFinalized();
|
||||
arguments.SetTypeAt(i, super_type_arg);
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
ASSERT(super_type_arg.IsType());
|
||||
unfinalized_type = super_type_arg.ptr();
|
||||
|
@ -755,10 +760,13 @@ AbstractTypePtr ClassFinalizer::FinalizeType(const AbstractType& type,
|
|||
// is_being_finalized mark bit.
|
||||
return type.ptr();
|
||||
}
|
||||
type.SetIsBeingFinalized();
|
||||
AbstractType& ref_type =
|
||||
AbstractType::Handle(zone, TypeRef::Cast(type).type());
|
||||
ref_type = FinalizeType(ref_type, finalization, pending_types);
|
||||
ASSERT(ref_type.IsFinalized());
|
||||
TypeRef::Cast(type).set_type(ref_type);
|
||||
ASSERT(type.IsFinalized());
|
||||
return type.ptr();
|
||||
}
|
||||
|
||||
|
@ -1563,7 +1571,7 @@ class CidRewriteVisitor : public ObjectVisitor {
|
|||
Map(param->untag()->parameterized_class_id_);
|
||||
} else if (obj->IsType()) {
|
||||
TypePtr type = Type::RawCast(obj);
|
||||
type->untag()->type_class_id_ = Map(type->untag()->type_class_id_);
|
||||
type->untag()->set_type_class_id(Map(type->untag()->type_class_id()));
|
||||
} else {
|
||||
intptr_t old_cid = obj->GetClassId();
|
||||
intptr_t new_cid = Map(old_cid);
|
||||
|
@ -1619,7 +1627,7 @@ void ClassFinalizer::RemapClassIds(intptr_t* old_to_new_cid) {
|
|||
// In the Dart VM heap the following instances directly use cids for the
|
||||
// computation of canonical hash codes:
|
||||
//
|
||||
// * TypePtr (due to UntaggedType::type_class_id_)
|
||||
// * TypePtr (due to UntaggedType::type_class_id)
|
||||
// * TypeParameterPtr (due to UntaggedTypeParameter::parameterized_class_id_)
|
||||
//
|
||||
// The following instances use cids for the computation of canonical hash codes
|
||||
|
|
|
@ -1296,8 +1296,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
|||
|
||||
// Check nullability.
|
||||
__ Bind(&equiv_cids);
|
||||
__ ldrb(R1, FieldAddress(R1, target::Type::nullability_offset()));
|
||||
__ ldrb(R2, FieldAddress(R2, target::Type::nullability_offset()));
|
||||
__ LoadAbstractTypeNullability(R1, R1);
|
||||
__ LoadAbstractTypeNullability(R2, R2);
|
||||
__ cmp(R1, Operand(R2));
|
||||
__ b(&check_legacy, NE);
|
||||
// Fall through to equal case if nullability is strictly equal.
|
||||
|
|
|
@ -1463,10 +1463,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
|||
|
||||
// Check nullability.
|
||||
__ Bind(&equiv_cids);
|
||||
__ ldr(R1, FieldAddress(R1, target::Type::nullability_offset()),
|
||||
kUnsignedByte);
|
||||
__ ldr(R2, FieldAddress(R2, target::Type::nullability_offset()),
|
||||
kUnsignedByte);
|
||||
__ LoadAbstractTypeNullability(R1, R1);
|
||||
__ LoadAbstractTypeNullability(R2, R2);
|
||||
__ cmp(R1, Operand(R2));
|
||||
__ b(&check_legacy, NE);
|
||||
// Fall through to equal case if nullability is strictly equal.
|
||||
|
|
|
@ -1432,8 +1432,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
|||
|
||||
// Check nullability.
|
||||
__ Bind(&equiv_cids);
|
||||
__ movzxb(EDI, FieldAddress(EDI, target::Type::nullability_offset()));
|
||||
__ movzxb(EBX, FieldAddress(EBX, target::Type::nullability_offset()));
|
||||
__ LoadAbstractTypeNullability(EDI, EDI);
|
||||
__ LoadAbstractTypeNullability(EBX, EBX);
|
||||
__ cmpl(EDI, EBX);
|
||||
__ j(NOT_EQUAL, &check_legacy, Assembler::kNearJump);
|
||||
// Fall through to equal case if nullability is strictly equal.
|
||||
|
|
|
@ -1487,8 +1487,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
|||
|
||||
// Check nullability.
|
||||
__ Bind(&equiv_cids);
|
||||
__ lbu(A0, FieldAddress(A0, target::Type::nullability_offset()));
|
||||
__ lbu(A1, FieldAddress(A1, target::Type::nullability_offset()));
|
||||
__ LoadAbstractTypeNullability(A0, A0);
|
||||
__ LoadAbstractTypeNullability(A1, A1);
|
||||
__ bne(A0, A1, &check_legacy);
|
||||
// Fall through to equal case if nullability is strictly equal.
|
||||
|
||||
|
|
|
@ -1341,8 +1341,8 @@ void AsmIntrinsifier::Type_equality(Assembler* assembler,
|
|||
|
||||
// Check nullability.
|
||||
__ Bind(&equiv_cids);
|
||||
__ movzxb(RCX, FieldAddress(RCX, target::Type::nullability_offset()));
|
||||
__ movzxb(RDX, FieldAddress(RDX, target::Type::nullability_offset()));
|
||||
__ LoadAbstractTypeNullability(RCX, RCX);
|
||||
__ LoadAbstractTypeNullability(RDX, RDX);
|
||||
__ cmpq(RCX, RDX);
|
||||
__ j(NOT_EQUAL, &check_legacy, Assembler::kNearJump);
|
||||
// Fall through to equal case if nullability is strictly equal.
|
||||
|
|
|
@ -441,17 +441,17 @@ class Assembler : public AssemblerBase {
|
|||
cmp(value, Operand(TMP));
|
||||
}
|
||||
|
||||
void CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kFunctionTypeCid, type, TMP);
|
||||
ldrb(TMP, FieldAddress(
|
||||
type, compiler::target::FunctionType::nullability_offset()));
|
||||
cmp(TMP, Operand(value));
|
||||
void LoadAbstractTypeNullability(Register dst, Register type) override {
|
||||
ldrb(dst,
|
||||
FieldAddress(type, compiler::target::AbstractType::flags_offset()));
|
||||
and_(dst, dst,
|
||||
Operand(compiler::target::UntaggedAbstractType::kNullabilityMask));
|
||||
}
|
||||
void CompareTypeNullabilityWith(Register type, int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kTypeCid, type, TMP);
|
||||
ldrb(TMP, FieldAddress(type, compiler::target::Type::nullability_offset()));
|
||||
cmp(TMP, Operand(value));
|
||||
void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) override {
|
||||
LoadAbstractTypeNullability(scratch, type);
|
||||
cmp(scratch, Operand(value));
|
||||
}
|
||||
|
||||
// Misc. functionality
|
||||
|
@ -869,6 +869,13 @@ class Assembler : public AssemblerBase {
|
|||
void LslImmediate(Register rd, int32_t shift) {
|
||||
LslImmediate(rd, rd, shift);
|
||||
}
|
||||
void LsrImmediate(Register rd, Register rn, int32_t shift) {
|
||||
ASSERT((shift >= 0) && (shift < kBitsPerInt32));
|
||||
Lsr(rd, rn, Operand(shift));
|
||||
}
|
||||
void LsrImmediate(Register rd, int32_t shift) override {
|
||||
LsrImmediate(rd, rd, shift);
|
||||
}
|
||||
|
||||
// Test rn and immediate. May clobber IP.
|
||||
void TestImmediate(Register rn, int32_t imm, Condition cond = AL);
|
||||
|
|
|
@ -648,20 +648,17 @@ class Assembler : public AssemblerBase {
|
|||
cmp(value, Operand(TMP), sz);
|
||||
}
|
||||
|
||||
void CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kFunctionTypeCid, type, TMP);
|
||||
ldr(TMP,
|
||||
FieldAddress(type,
|
||||
compiler::target::FunctionType::nullability_offset()),
|
||||
void LoadAbstractTypeNullability(Register dst, Register type) override {
|
||||
ldr(dst, FieldAddress(type, compiler::target::AbstractType::flags_offset()),
|
||||
kUnsignedByte);
|
||||
cmp(TMP, Operand(value));
|
||||
AndImmediate(dst, dst,
|
||||
compiler::target::UntaggedAbstractType::kNullabilityMask);
|
||||
}
|
||||
void CompareTypeNullabilityWith(Register type, int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kTypeCid, type, TMP);
|
||||
ldr(TMP, FieldAddress(type, compiler::target::Type::nullability_offset()),
|
||||
kUnsignedByte);
|
||||
cmp(TMP, Operand(value));
|
||||
void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) override {
|
||||
LoadAbstractTypeNullability(scratch, type);
|
||||
cmp(scratch, Operand(value));
|
||||
}
|
||||
|
||||
bool use_far_branches() const {
|
||||
|
@ -1707,6 +1704,9 @@ class Assembler : public AssemblerBase {
|
|||
ASSERT((shift >= 0) && (shift < reg_size));
|
||||
ubfm(rd, rn, shift, reg_size - 1, sz);
|
||||
}
|
||||
void LsrImmediate(Register rd, int32_t shift) override {
|
||||
LsrImmediate(rd, rd, shift);
|
||||
}
|
||||
void AsrImmediate(Register rd,
|
||||
Register rn,
|
||||
int shift,
|
||||
|
|
|
@ -782,30 +782,24 @@ class AssemblerBase : public StackResource {
|
|||
Register address,
|
||||
int32_t offset = 0) = 0;
|
||||
|
||||
// Retrieves nullability from a FunctionTypePtr in [type] and compares it
|
||||
// to [value].
|
||||
//
|
||||
// TODO(dartbug.com/47034): Change how nullability is stored so that it
|
||||
// can be accessed without checking the class id first.
|
||||
virtual void CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) = 0;
|
||||
// Loads nullability from an AbstractType [type] to [dst].
|
||||
virtual void LoadAbstractTypeNullability(Register dst, Register type) = 0;
|
||||
// Loads nullability from an AbstractType [type] and compares it
|
||||
// to [value]. Clobbers [scratch].
|
||||
virtual void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) = 0;
|
||||
|
||||
// Retrieves nullability from a TypePtr in [type] and compares it to [value].
|
||||
//
|
||||
// TODO(dartbug.com/47034): Change how nullability is stored so that it
|
||||
// can be accessed without checking the class id first.
|
||||
virtual void CompareTypeNullabilityWith(Register type, int8_t value) = 0;
|
||||
virtual void LsrImmediate(Register dst, int32_t shift) = 0;
|
||||
|
||||
void LoadTypeClassId(Register dst, Register src) {
|
||||
#if !defined(TARGET_ARCH_IA32)
|
||||
EnsureHasClassIdInDEBUG(kTypeCid, src, TMP);
|
||||
#endif
|
||||
ASSERT(!compiler::target::UntaggedType::kTypeClassIdIsSigned);
|
||||
ASSERT_EQUAL(compiler::target::UntaggedType::kTypeClassIdBitSize,
|
||||
kBitsPerInt16);
|
||||
LoadFieldFromOffset(dst, src,
|
||||
compiler::target::Type::type_class_id_offset(),
|
||||
kUnsignedTwoBytes);
|
||||
compiler::target::AbstractType::flags_offset(),
|
||||
kUnsignedFourBytes);
|
||||
LsrImmediate(dst, compiler::target::UntaggedType::kTypeClassIdShift);
|
||||
}
|
||||
|
||||
virtual void EnsureHasClassIdInDEBUG(intptr_t cid,
|
||||
|
|
|
@ -766,6 +766,9 @@ class Assembler : public AssemblerBase {
|
|||
void LslImmediate(Register dst, int32_t shift) {
|
||||
shll(dst, Immediate(shift));
|
||||
}
|
||||
void LsrImmediate(Register dst, int32_t shift) override {
|
||||
shrl(dst, Immediate(shift));
|
||||
}
|
||||
|
||||
void CompareImmediate(Register reg, int32_t immediate) {
|
||||
cmpl(reg, Immediate(immediate));
|
||||
|
@ -878,15 +881,17 @@ class Assembler : public AssemblerBase {
|
|||
cmpxchgl(address, reg);
|
||||
}
|
||||
|
||||
void CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) override {
|
||||
cmpb(FieldAddress(type,
|
||||
compiler::target::FunctionType::nullability_offset()),
|
||||
Immediate(value));
|
||||
void LoadAbstractTypeNullability(Register dst, Register type) override {
|
||||
movzxb(dst,
|
||||
FieldAddress(type, compiler::target::AbstractType::flags_offset()));
|
||||
andl(dst,
|
||||
Immediate(compiler::target::UntaggedAbstractType::kNullabilityMask));
|
||||
}
|
||||
void CompareTypeNullabilityWith(Register type, int8_t value) override {
|
||||
cmpb(FieldAddress(type, compiler::target::Type::nullability_offset()),
|
||||
Immediate(value));
|
||||
void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) override {
|
||||
LoadAbstractTypeNullability(scratch, type);
|
||||
cmpl(scratch, Immediate(value));
|
||||
}
|
||||
|
||||
void EnterFrame(intptr_t frame_space);
|
||||
|
|
|
@ -2389,17 +2389,16 @@ void Assembler::CompareWithMemoryValue(Register value, Address address) {
|
|||
CompareRegisters(value, TMP2);
|
||||
}
|
||||
|
||||
void Assembler::CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) {
|
||||
EnsureHasClassIdInDEBUG(kFunctionTypeCid, type, TMP);
|
||||
lbu(TMP,
|
||||
FieldAddress(type, compiler::target::FunctionType::nullability_offset()));
|
||||
CompareImmediate(TMP, value);
|
||||
void Assembler::LoadAbstractTypeNullability(Register dst, Register type) {
|
||||
lbu(dst, FieldAddress(type, compiler::target::AbstractType::flags_offset()));
|
||||
andi(dst, dst, compiler::target::UntaggedAbstractType::kNullabilityMask);
|
||||
}
|
||||
void Assembler::CompareTypeNullabilityWith(Register type, int8_t value) {
|
||||
EnsureHasClassIdInDEBUG(kTypeCid, type, TMP);
|
||||
lbu(TMP, FieldAddress(type, compiler::target::Type::nullability_offset()));
|
||||
CompareImmediate(TMP, value);
|
||||
|
||||
void Assembler::CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) {
|
||||
LoadAbstractTypeNullability(scratch, type);
|
||||
CompareImmediate(scratch, value);
|
||||
}
|
||||
|
||||
void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
|
||||
|
|
|
@ -846,8 +846,10 @@ class Assembler : public MicroAssembler {
|
|||
|
||||
void CompareWithMemoryValue(Register value, Address address);
|
||||
|
||||
void CompareFunctionTypeNullabilityWith(Register type, int8_t value) override;
|
||||
void CompareTypeNullabilityWith(Register type, int8_t value) override;
|
||||
void LoadAbstractTypeNullability(Register dst, Register type) override;
|
||||
void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) override;
|
||||
|
||||
// Debugging and bringup support.
|
||||
void Breakpoint() override { trap(); }
|
||||
|
@ -986,6 +988,9 @@ class Assembler : public MicroAssembler {
|
|||
void LslImmediate(Register rd, int32_t shift) {
|
||||
slli(rd, rd, shift);
|
||||
}
|
||||
void LsrImmediate(Register rd, int32_t shift) override {
|
||||
srli(rd, rd, shift);
|
||||
}
|
||||
void TestImmediate(Register rn, intx_t imm, OperandSize sz = kWordBytes);
|
||||
void CompareImmediate(Register rn, intx_t imm, OperandSize sz = kWordBytes);
|
||||
|
||||
|
|
|
@ -594,6 +594,9 @@ class Assembler : public AssemblerBase {
|
|||
void LslImmediate(Register dst, int32_t shift) {
|
||||
shlq(dst, Immediate(shift));
|
||||
}
|
||||
void LsrImmediate(Register dst, int32_t shift) override {
|
||||
shrq(dst, Immediate(shift));
|
||||
}
|
||||
|
||||
void shldq(Register dst, Register src, Register shifter) {
|
||||
ASSERT(shifter == RCX);
|
||||
|
@ -1219,17 +1222,17 @@ class Assembler : public AssemblerBase {
|
|||
OBJ(cmp)(value, FieldAddress(base, offset));
|
||||
}
|
||||
|
||||
void CompareFunctionTypeNullabilityWith(Register type,
|
||||
int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kFunctionTypeCid, type, TMP);
|
||||
cmpb(FieldAddress(type,
|
||||
compiler::target::FunctionType::nullability_offset()),
|
||||
Immediate(value));
|
||||
void LoadAbstractTypeNullability(Register dst, Register type) override {
|
||||
movzxb(dst,
|
||||
FieldAddress(type, compiler::target::AbstractType::flags_offset()));
|
||||
andl(dst,
|
||||
Immediate(compiler::target::UntaggedAbstractType::kNullabilityMask));
|
||||
}
|
||||
void CompareTypeNullabilityWith(Register type, int8_t value) override {
|
||||
EnsureHasClassIdInDEBUG(kTypeCid, type, TMP);
|
||||
cmpb(FieldAddress(type, compiler::target::Type::nullability_offset()),
|
||||
Immediate(value));
|
||||
void CompareAbstractTypeNullabilityWith(Register type,
|
||||
/*Nullability*/ int8_t value,
|
||||
Register scratch) override {
|
||||
LoadAbstractTypeNullability(scratch, type);
|
||||
cmpl(scratch, Immediate(value));
|
||||
}
|
||||
|
||||
void RestoreCodePointer();
|
||||
|
|
|
@ -183,8 +183,7 @@ NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(FOR_EACH_NATIVE_SLOT)
|
|||
V(FunctionType, UntaggedFunctionType, packed_type_parameter_counts, Uint16, \
|
||||
FINAL) \
|
||||
V(PointerBase, UntaggedPointerBase, data, IntPtr, VAR) \
|
||||
V(Record, UntaggedRecord, num_fields, Int32, FINAL) \
|
||||
V(TypeParameter, UntaggedTypeParameter, flags, Uint8, FINAL)
|
||||
V(Record, UntaggedRecord, num_fields, Int32, FINAL)
|
||||
|
||||
// For uses that do not need the exact_type (boxed) or representation (unboxed)
|
||||
// or whether a boxed native slot is nullable. (Generally, such users only need
|
||||
|
|
|
@ -391,12 +391,15 @@ const word UntaggedObject::kTagBitsSizeTagPos =
|
|||
|
||||
const word UntaggedAbstractType::kTypeStateFinalizedInstantiated =
|
||||
dart::UntaggedAbstractType::kFinalizedInstantiated;
|
||||
const word UntaggedAbstractType::kTypeStateShift =
|
||||
dart::UntaggedAbstractType::kTypeStateShift;
|
||||
const word UntaggedAbstractType::kTypeStateBits =
|
||||
dart::UntaggedAbstractType::kTypeStateBits;
|
||||
const word UntaggedAbstractType::kNullabilityMask =
|
||||
dart::UntaggedAbstractType::kNullabilityMask;
|
||||
|
||||
const bool UntaggedType::kTypeClassIdIsSigned =
|
||||
std::is_signed<decltype(dart::UntaggedType::type_class_id_)>::value;
|
||||
|
||||
const word UntaggedType::kTypeClassIdBitSize =
|
||||
sizeof(dart::UntaggedType::type_class_id_) * kBitsPerByte;
|
||||
const word UntaggedType::kTypeClassIdShift =
|
||||
dart::UntaggedType::kTypeClassIdShift;
|
||||
|
||||
const word UntaggedObject::kBarrierOverlapShift =
|
||||
dart::UntaggedObject::kBarrierOverlapShift;
|
||||
|
|
|
@ -432,12 +432,14 @@ class UntaggedObject : public AllStatic {
|
|||
class UntaggedAbstractType : public AllStatic {
|
||||
public:
|
||||
static const word kTypeStateFinalizedInstantiated;
|
||||
static const word kTypeStateShift;
|
||||
static const word kTypeStateBits;
|
||||
static const word kNullabilityMask;
|
||||
};
|
||||
|
||||
class UntaggedType : public AllStatic {
|
||||
public:
|
||||
static const bool kTypeClassIdIsSigned;
|
||||
static const word kTypeClassIdBitSize;
|
||||
static const word kTypeClassIdShift;
|
||||
};
|
||||
|
||||
class Object : public AllStatic {
|
||||
|
@ -695,6 +697,7 @@ class Pointer : public AllStatic {
|
|||
|
||||
class AbstractType : public AllStatic {
|
||||
public:
|
||||
static word flags_offset();
|
||||
static word type_test_stub_entry_point_offset();
|
||||
static word InstanceSize();
|
||||
FINAL_CLASS();
|
||||
|
@ -703,10 +706,7 @@ class AbstractType : public AllStatic {
|
|||
class Type : public AllStatic {
|
||||
public:
|
||||
static word hash_offset();
|
||||
static word type_state_offset();
|
||||
static word arguments_offset();
|
||||
static word type_class_id_offset();
|
||||
static word nullability_offset();
|
||||
static word InstanceSize();
|
||||
FINAL_CLASS();
|
||||
};
|
||||
|
@ -714,13 +714,11 @@ class Type : public AllStatic {
|
|||
class FunctionType : public AllStatic {
|
||||
public:
|
||||
static word hash_offset();
|
||||
static word type_state_offset();
|
||||
static word packed_parameter_counts_offset();
|
||||
static word packed_type_parameter_counts_offset();
|
||||
static word named_parameter_names_offset();
|
||||
static word parameter_types_offset();
|
||||
static word type_parameters_offset();
|
||||
static word nullability_offset();
|
||||
static word InstanceSize();
|
||||
FINAL_CLASS();
|
||||
};
|
||||
|
@ -966,12 +964,10 @@ class Bool : public AllStatic {
|
|||
class TypeParameter : public AllStatic {
|
||||
public:
|
||||
static word bound_offset();
|
||||
static word flags_offset();
|
||||
static word InstanceSize();
|
||||
FINAL_CLASS();
|
||||
static word parameterized_class_id_offset();
|
||||
static word index_offset();
|
||||
static word nullability_offset();
|
||||
};
|
||||
|
||||
class LibraryPrefix : public AllStatic {
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -88,6 +88,7 @@
|
|||
CONSTANT(SubtypeTestCache, kTestEntryLength) \
|
||||
CONSTANT(SubtypeTestCache, kTestResult) \
|
||||
CONSTANT(TypeArguments, kMaxElements) \
|
||||
FIELD(AbstractType, flags_offset) \
|
||||
FIELD(AbstractType, type_test_stub_entry_point_offset) \
|
||||
FIELD(ArgumentsDescriptor, count_offset) \
|
||||
FIELD(ArgumentsDescriptor, size_offset) \
|
||||
|
@ -336,9 +337,6 @@
|
|||
FIELD(TwoByteString, data_offset) \
|
||||
FIELD(Type, arguments_offset) \
|
||||
FIELD(Type, hash_offset) \
|
||||
FIELD(Type, type_class_id_offset) \
|
||||
FIELD(Type, type_state_offset) \
|
||||
FIELD(Type, nullability_offset) \
|
||||
FIELD(Finalizer, type_arguments_offset) \
|
||||
FIELD(Finalizer, callback_offset) \
|
||||
FIELD(FinalizerBase, all_entries_offset) \
|
||||
|
@ -354,14 +352,12 @@
|
|||
FIELD(NativeFinalizer, callback_offset) \
|
||||
FIELD(FunctionType, hash_offset) \
|
||||
FIELD(FunctionType, named_parameter_names_offset) \
|
||||
FIELD(FunctionType, nullability_offset) \
|
||||
FIELD(FunctionType, packed_parameter_counts_offset) \
|
||||
FIELD(FunctionType, packed_type_parameter_counts_offset) \
|
||||
FIELD(FunctionType, parameter_types_offset) \
|
||||
FIELD(FunctionType, type_parameters_offset) \
|
||||
FIELD(TypeParameter, parameterized_class_id_offset) \
|
||||
FIELD(TypeParameter, index_offset) \
|
||||
FIELD(TypeParameter, nullability_offset) \
|
||||
FIELD(TypeArguments, instantiations_offset) \
|
||||
FIELD(TypeArguments, length_offset) \
|
||||
FIELD(TypeArguments, nullability_offset) \
|
||||
|
@ -371,7 +367,6 @@
|
|||
FIELD(TypeParameters, bounds_offset) \
|
||||
FIELD(TypeParameters, defaults_offset) \
|
||||
FIELD(TypeParameter, bound_offset) \
|
||||
FIELD(TypeParameter, flags_offset) \
|
||||
FIELD(TypeRef, type_offset) \
|
||||
FIELD(TypedDataBase, length_offset) \
|
||||
FIELD(TypedDataView, typed_data_offset) \
|
||||
|
|
|
@ -312,50 +312,27 @@ static void BuildInstantiateTypeParameterStub(Assembler* assembler,
|
|||
__ LoadClassId(InstantiateTypeABI::kScratchReg,
|
||||
InstantiateTypeABI::kResultTypeReg);
|
||||
|
||||
// The loaded value from the TAV can be [Type], [FunctionType] or [TypeRef].
|
||||
// Handle/unwrap TypeRefs in runtime.
|
||||
__ CompareImmediate(InstantiateTypeABI::kScratchReg, kTypeRefCid);
|
||||
__ BranchIf(EQUAL, &runtime_call);
|
||||
|
||||
// Handle [Type]s.
|
||||
__ CompareImmediate(InstantiateTypeABI::kScratchReg, kTypeCid);
|
||||
__ BranchIf(NOT_EQUAL, &type_parameter_value_is_not_type);
|
||||
switch (nullability) {
|
||||
case Nullability::kNonNullable:
|
||||
__ Ret();
|
||||
break;
|
||||
case Nullability::kNullable:
|
||||
__ CompareTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
InstantiateTypeABI::kResultTypeReg,
|
||||
static_cast<int8_t>(Nullability::kNullable));
|
||||
static_cast<int8_t>(Nullability::kNullable),
|
||||
InstantiateTypeABI::kScratchReg);
|
||||
__ BranchIf(NOT_EQUAL, &runtime_call);
|
||||
__ Ret();
|
||||
break;
|
||||
case Nullability::kLegacy:
|
||||
__ CompareTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
InstantiateTypeABI::kResultTypeReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
__ BranchIf(EQUAL, &runtime_call);
|
||||
__ Ret();
|
||||
}
|
||||
|
||||
// TODO(dartbug.com/49719)
|
||||
// Handle [FunctionType]s.
|
||||
__ Bind(&type_parameter_value_is_not_type);
|
||||
__ CompareImmediate(InstantiateTypeABI::kScratchReg, kFunctionTypeCid);
|
||||
__ BranchIf(NOT_EQUAL, &runtime_call);
|
||||
switch (nullability) {
|
||||
case Nullability::kNonNullable:
|
||||
__ Ret();
|
||||
break;
|
||||
case Nullability::kNullable:
|
||||
__ CompareFunctionTypeNullabilityWith(
|
||||
InstantiateTypeABI::kResultTypeReg,
|
||||
static_cast<int8_t>(Nullability::kNullable));
|
||||
__ BranchIf(NOT_EQUAL, &runtime_call);
|
||||
__ Ret();
|
||||
break;
|
||||
case Nullability::kLegacy:
|
||||
__ CompareFunctionTypeNullabilityWith(
|
||||
InstantiateTypeABI::kResultTypeReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
static_cast<int8_t>(Nullability::kNonNullable),
|
||||
InstantiateTypeABI::kScratchReg);
|
||||
__ BranchIf(EQUAL, &runtime_call);
|
||||
__ Ret();
|
||||
}
|
||||
|
@ -520,8 +497,9 @@ static void GenerateTypeIsTopTypeForSubtyping(Assembler* assembler,
|
|||
__ BranchIf(NOT_EQUAL, &done, compiler::Assembler::kNearJump);
|
||||
if (null_safety) {
|
||||
// Instance type isn't a top type if non-nullable in null safe mode.
|
||||
__ CompareTypeNullabilityWith(
|
||||
scratch1_reg, static_cast<int8_t>(Nullability::kNonNullable));
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
scratch1_reg, static_cast<int8_t>(Nullability::kNonNullable),
|
||||
scratch2_reg);
|
||||
__ BranchIf(EQUAL, &done, compiler::Assembler::kNearJump);
|
||||
}
|
||||
__ Bind(&is_top_type);
|
||||
|
@ -619,8 +597,9 @@ static void GenerateNullIsAssignableToType(Assembler* assembler,
|
|||
compiler::Label is_not_type;
|
||||
__ CompareClassId(kCurrentTypeReg, kTypeCid, kScratchReg);
|
||||
__ BranchIf(NOT_EQUAL, &is_not_type, compiler::Assembler::kNearJump);
|
||||
__ CompareTypeNullabilityWith(
|
||||
kCurrentTypeReg, static_cast<int8_t>(Nullability::kNonNullable));
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
kCurrentTypeReg, static_cast<int8_t>(Nullability::kNonNullable),
|
||||
kScratchReg);
|
||||
__ BranchIf(NOT_EQUAL, &is_assignable);
|
||||
// FutureOr is a special case because it may have the non-nullable bit set,
|
||||
// but FutureOr<T> functions as the union of T and Future<T>, so it must be
|
||||
|
@ -644,11 +623,9 @@ static void GenerateNullIsAssignableToType(Assembler* assembler,
|
|||
__ Bind(&is_not_type);
|
||||
// Null is assignable to a type parameter only if it is nullable or if the
|
||||
// instantiation is nullable.
|
||||
__ LoadFieldFromOffset(
|
||||
kScratchReg, kCurrentTypeReg,
|
||||
compiler::target::TypeParameter::nullability_offset(), kByte);
|
||||
__ CompareImmediate(kScratchReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
kCurrentTypeReg, static_cast<int8_t>(Nullability::kNonNullable),
|
||||
kScratchReg);
|
||||
__ BranchIf(NOT_EQUAL, &is_assignable);
|
||||
|
||||
// Don't set kScratchReg in here as on IA32, that's the function TAV reg.
|
||||
|
@ -878,10 +855,15 @@ void StubCodeCompiler::GenerateSlowTypeTestStub(Assembler* assembler) {
|
|||
|
||||
// Check whether this [Type] is instantiated/uninstantiated.
|
||||
__ LoadFieldFromOffset(TypeTestABI::kScratchReg, TypeTestABI::kDstTypeReg,
|
||||
target::Type::type_state_offset(), kByte);
|
||||
target::AbstractType::flags_offset(), kByte);
|
||||
__ AndImmediate(
|
||||
TypeTestABI::kScratchReg,
|
||||
Utils::NBitMask<int32_t>(target::UntaggedAbstractType::kTypeStateBits)
|
||||
<< target::UntaggedAbstractType::kTypeStateShift);
|
||||
__ CompareImmediate(
|
||||
TypeTestABI::kScratchReg,
|
||||
target::UntaggedAbstractType::kTypeStateFinalizedInstantiated);
|
||||
target::UntaggedAbstractType::kTypeStateFinalizedInstantiated
|
||||
<< target::UntaggedAbstractType::kTypeStateShift);
|
||||
__ BranchIf(NOT_EQUAL, &is_complex_case, Assembler::kNearJump);
|
||||
|
||||
// This [Type] could be a FutureOr. Subtype2TestCache does not support Smi.
|
||||
|
|
|
@ -10554,20 +10554,15 @@ FunctionTypePtr FunctionType::New(intptr_t num_parent_type_arguments,
|
|||
result.set_packed_type_parameter_counts(0);
|
||||
result.set_named_parameter_names(Object::empty_array());
|
||||
result.SetNumParentTypeArguments(num_parent_type_arguments);
|
||||
result.set_nullability(nullability);
|
||||
result.SetHash(0);
|
||||
result.StoreNonPointer(&result.untag()->type_state_,
|
||||
UntaggedType::kAllocated);
|
||||
result.set_flags(0);
|
||||
result.set_nullability(nullability);
|
||||
result.set_type_state(UntaggedAbstractType::kAllocated);
|
||||
result.InitializeTypeTestingStubNonAtomic(
|
||||
Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
|
||||
return result.ptr();
|
||||
}
|
||||
|
||||
void FunctionType::set_type_state(uint8_t state) const {
|
||||
ASSERT(state <= UntaggedFunctionType::kFinalizedUninstantiated);
|
||||
StoreNonPointer(&untag()->type_state_, state);
|
||||
}
|
||||
|
||||
const char* FunctionType::ToUserVisibleCString() const {
|
||||
Zone* zone = Thread::Current()->zone();
|
||||
ZoneTextBuffer printer(zone);
|
||||
|
@ -20133,12 +20128,6 @@ void AbstractType::set_arguments(const TypeArguments& value) const {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
Nullability AbstractType::nullability() const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
return Nullability::kNullable;
|
||||
}
|
||||
|
||||
bool AbstractType::IsStrictlyNonNullable() const {
|
||||
// Null can be assigned to legacy and nullable types.
|
||||
if (!IsNonNullable()) {
|
||||
|
@ -20259,26 +20248,32 @@ bool AbstractType::IsInstantiated(Genericity genericity,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool AbstractType::IsFinalized() const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
|
||||
void AbstractType::SetIsFinalized() const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool AbstractType::IsBeingFinalized() const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
ASSERT(!IsFinalized());
|
||||
set_type_state(IsInstantiated()
|
||||
? UntaggedAbstractType::kFinalizedInstantiated
|
||||
: UntaggedAbstractType::kFinalizedUninstantiated);
|
||||
}
|
||||
|
||||
void AbstractType::SetIsBeingFinalized() const {
|
||||
// AbstractType is an abstract class.
|
||||
UNREACHABLE();
|
||||
ASSERT(!IsFinalized() && !IsBeingFinalized());
|
||||
set_type_state(UntaggedAbstractType::kBeingFinalized);
|
||||
}
|
||||
|
||||
void AbstractType::set_flags(uint32_t value) const {
|
||||
StoreNonPointer(&untag()->flags_, value);
|
||||
}
|
||||
|
||||
void AbstractType::set_type_state(UntaggedAbstractType::TypeState value) const {
|
||||
ASSERT(!IsCanonical());
|
||||
set_flags(
|
||||
UntaggedAbstractType::TypeStateBits::update(value, untag()->flags_));
|
||||
}
|
||||
|
||||
void AbstractType::set_nullability(Nullability value) const {
|
||||
ASSERT(!IsCanonical());
|
||||
set_flags(UntaggedAbstractType::NullabilityBits::update(
|
||||
static_cast<uint8_t>(value), untag()->flags_));
|
||||
}
|
||||
|
||||
bool AbstractType::IsEquivalent(const Instance& other,
|
||||
|
@ -21066,34 +21061,6 @@ TypePtr Type::NewNonParameterizedType(const Class& type_class) {
|
|||
return type.ptr();
|
||||
}
|
||||
|
||||
void Type::SetIsFinalized() const {
|
||||
ASSERT(!IsFinalized());
|
||||
if (IsInstantiated()) {
|
||||
set_type_state(UntaggedType::kFinalizedInstantiated);
|
||||
} else {
|
||||
set_type_state(UntaggedType::kFinalizedUninstantiated);
|
||||
}
|
||||
}
|
||||
|
||||
void FunctionType::SetIsFinalized() const {
|
||||
ASSERT(!IsFinalized());
|
||||
if (IsInstantiated()) {
|
||||
set_type_state(UntaggedFunctionType::kFinalizedInstantiated);
|
||||
} else {
|
||||
set_type_state(UntaggedFunctionType::kFinalizedUninstantiated);
|
||||
}
|
||||
}
|
||||
|
||||
void Type::SetIsBeingFinalized() const {
|
||||
ASSERT(!IsFinalized() && !IsBeingFinalized());
|
||||
set_type_state(UntaggedType::kBeingFinalized);
|
||||
}
|
||||
|
||||
void FunctionType::SetIsBeingFinalized() const {
|
||||
ASSERT(!IsFinalized() && !IsBeingFinalized());
|
||||
set_type_state(UntaggedFunctionType::kBeingFinalized);
|
||||
}
|
||||
|
||||
TypePtr Type::ToNullability(Nullability value, Heap::Space space) const {
|
||||
if (nullability() == value) {
|
||||
return ptr();
|
||||
|
@ -21151,7 +21118,7 @@ FunctionTypePtr FunctionType::ToNullability(Nullability value,
|
|||
}
|
||||
|
||||
classid_t Type::type_class_id() const {
|
||||
return untag()->type_class_id_;
|
||||
return untag()->type_class_id();
|
||||
}
|
||||
|
||||
ClassPtr Type::type_class() const {
|
||||
|
@ -21161,11 +21128,11 @@ ClassPtr Type::type_class() const {
|
|||
bool Type::IsInstantiated(Genericity genericity,
|
||||
intptr_t num_free_fun_type_params,
|
||||
TrailPtr trail) const {
|
||||
if (untag()->type_state_ == UntaggedType::kFinalizedInstantiated) {
|
||||
if (type_state() == UntaggedType::kFinalizedInstantiated) {
|
||||
return true;
|
||||
}
|
||||
if ((genericity == kAny) && (num_free_fun_type_params == kAllFree) &&
|
||||
(untag()->type_state_ == UntaggedType::kFinalizedUninstantiated)) {
|
||||
(type_state() == UntaggedType::kFinalizedUninstantiated)) {
|
||||
return false;
|
||||
}
|
||||
if (arguments() == TypeArguments::null()) {
|
||||
|
@ -21723,12 +21690,12 @@ TypePtr Type::New(const Class& clazz,
|
|||
Heap::Space space) {
|
||||
Zone* Z = Thread::Current()->zone();
|
||||
const Type& result = Type::Handle(Z, Type::New(space));
|
||||
result.set_type_class(clazz);
|
||||
result.set_arguments(arguments);
|
||||
result.SetHash(0);
|
||||
result.StoreNonPointer(&result.untag()->type_state_,
|
||||
UntaggedType::kAllocated);
|
||||
result.set_flags(0);
|
||||
result.set_nullability(nullability);
|
||||
result.set_type_state(UntaggedAbstractType::kAllocated);
|
||||
result.set_type_class(clazz);
|
||||
|
||||
result.InitializeTypeTestingStubNonAtomic(
|
||||
Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
|
||||
|
@ -21736,19 +21703,13 @@ TypePtr Type::New(const Class& clazz,
|
|||
}
|
||||
|
||||
void Type::set_type_class_id(intptr_t id) const {
|
||||
COMPILE_ASSERT(
|
||||
std::is_unsigned<decltype(UntaggedType::type_class_id_)>::value);
|
||||
ASSERT(Utils::IsUint(sizeof(untag()->type_class_id_) * kBitsPerByte, id));
|
||||
COMPILE_ASSERT(std::is_unsigned<ClassIdTagType>::value);
|
||||
ASSERT(Utils::IsUint(sizeof(ClassIdTagType) * kBitsPerByte, id));
|
||||
// We should never need a Type object for a top-level class.
|
||||
ASSERT(!ClassTable::IsTopLevelCid(id));
|
||||
ASSERT(id != kIllegalCid);
|
||||
ASSERT(!IsInternalOnlyClassId(id));
|
||||
StoreNonPointer(&untag()->type_class_id_, id);
|
||||
}
|
||||
|
||||
void Type::set_type_state(uint8_t state) const {
|
||||
ASSERT(state <= UntaggedType::kFinalizedUninstantiated);
|
||||
StoreNonPointer(&untag()->type_state_, state);
|
||||
untag()->set_type_class_id(id);
|
||||
}
|
||||
|
||||
const char* Type::ToCString() const {
|
||||
|
@ -22064,6 +22025,12 @@ AbstractTypePtr TypeRef::InstantiateFrom(
|
|||
|
||||
void TypeRef::set_type(const AbstractType& value) const {
|
||||
ASSERT(!value.IsTypeRef());
|
||||
if (value.IsNull()) {
|
||||
ASSERT(!IsFinalized());
|
||||
} else {
|
||||
set_type_state(value.type_state());
|
||||
set_nullability(value.nullability());
|
||||
}
|
||||
untag()->set_type(value.ptr());
|
||||
}
|
||||
|
||||
|
@ -22165,23 +22132,6 @@ const char* TypeRef::ToCString() const {
|
|||
return printer.buffer();
|
||||
}
|
||||
|
||||
void TypeParameter::SetIsFinalized() const {
|
||||
ASSERT(!IsFinalized());
|
||||
set_flags(UntaggedTypeParameter::FinalizedBit::update(
|
||||
true, UntaggedTypeParameter::BeingFinalizedBit::update(false,
|
||||
untag()->flags_)));
|
||||
}
|
||||
|
||||
void TypeParameter::SetIsBeingFinalized() const {
|
||||
ASSERT(!IsFinalized());
|
||||
set_flags(
|
||||
UntaggedTypeParameter::BeingFinalizedBit::update(true, untag()->flags_));
|
||||
}
|
||||
|
||||
void TypeParameter::set_nullability(Nullability value) const {
|
||||
StoreNonPointer(&untag()->nullability_, static_cast<uint8_t>(value));
|
||||
}
|
||||
|
||||
TypeParameterPtr TypeParameter::ToNullability(Nullability value,
|
||||
Heap::Space space) const {
|
||||
if (nullability() == value) {
|
||||
|
@ -22539,19 +22489,16 @@ TypeParameterPtr TypeParameter::New(const Class& parameterized_class,
|
|||
result.set_base(base);
|
||||
result.set_index(index);
|
||||
result.set_bound(bound);
|
||||
result.SetHash(0);
|
||||
result.set_flags(0);
|
||||
result.set_nullability(nullability);
|
||||
result.SetHash(0);
|
||||
result.set_type_state(UntaggedAbstractType::kAllocated);
|
||||
|
||||
result.InitializeTypeTestingStubNonAtomic(
|
||||
Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
|
||||
return result.ptr();
|
||||
}
|
||||
|
||||
void TypeParameter::set_flags(uint8_t flags) const {
|
||||
StoreNonPointer(&untag()->flags_, flags);
|
||||
}
|
||||
|
||||
const char* TypeParameter::CanonicalNameCString(bool is_class_type_parameter,
|
||||
intptr_t base,
|
||||
intptr_t index) {
|
||||
|
@ -27252,34 +27199,15 @@ RecordTypePtr RecordType::New(const Array& field_types,
|
|||
const RecordType& result = RecordType::Handle(Z, RecordType::New(space));
|
||||
result.set_field_types(field_types);
|
||||
result.set_field_names(field_names);
|
||||
result.set_nullability(nullability);
|
||||
result.SetHash(0);
|
||||
result.StoreNonPointer(&result.untag()->type_state_,
|
||||
UntaggedType::kAllocated);
|
||||
result.set_flags(0);
|
||||
result.set_nullability(nullability);
|
||||
result.set_type_state(UntaggedAbstractType::kAllocated);
|
||||
result.InitializeTypeTestingStubNonAtomic(
|
||||
Code::Handle(Z, TypeTestingStubGenerator::DefaultCodeForType(result)));
|
||||
return result.ptr();
|
||||
}
|
||||
|
||||
void RecordType::set_type_state(uint8_t state) const {
|
||||
ASSERT(state <= UntaggedRecordType::kFinalizedUninstantiated);
|
||||
StoreNonPointer(&untag()->type_state_, state);
|
||||
}
|
||||
|
||||
void RecordType::SetIsFinalized() const {
|
||||
ASSERT(!IsFinalized());
|
||||
if (IsInstantiated()) {
|
||||
set_type_state(UntaggedRecordType::kFinalizedInstantiated);
|
||||
} else {
|
||||
set_type_state(UntaggedRecordType::kFinalizedUninstantiated);
|
||||
}
|
||||
}
|
||||
|
||||
void RecordType::SetIsBeingFinalized() const {
|
||||
ASSERT(!IsFinalized() && !IsBeingFinalized());
|
||||
set_type_state(UntaggedRecordType::kBeingFinalized);
|
||||
}
|
||||
|
||||
RecordTypePtr RecordType::ToNullability(Nullability value,
|
||||
Heap::Space space) const {
|
||||
if (nullability() == value) {
|
||||
|
|
|
@ -8165,12 +8165,25 @@ class TypeArguments : public Instance {
|
|||
// Subclasses of AbstractType are Type and TypeParameter.
|
||||
class AbstractType : public Instance {
|
||||
public:
|
||||
virtual bool IsFinalized() const;
|
||||
virtual void SetIsFinalized() const;
|
||||
virtual bool IsBeingFinalized() const;
|
||||
virtual void SetIsBeingFinalized() const;
|
||||
static intptr_t flags_offset() {
|
||||
return OFFSET_OF(UntaggedAbstractType, flags_);
|
||||
}
|
||||
|
||||
virtual Nullability nullability() const;
|
||||
bool IsFinalized() const {
|
||||
const auto state = type_state();
|
||||
return (state == UntaggedAbstractType::kFinalizedInstantiated) ||
|
||||
(state == UntaggedAbstractType::kFinalizedUninstantiated);
|
||||
}
|
||||
void SetIsFinalized() const;
|
||||
bool IsBeingFinalized() const {
|
||||
return type_state() == UntaggedAbstractType::kBeingFinalized;
|
||||
}
|
||||
void SetIsBeingFinalized() const;
|
||||
|
||||
Nullability nullability() const {
|
||||
return static_cast<Nullability>(
|
||||
UntaggedAbstractType::NullabilityBits::decode(untag()->flags_));
|
||||
}
|
||||
// Returns true if type has '?' nullability suffix, or it is a
|
||||
// built-in type which is always nullable (Null, dynamic or void).
|
||||
bool IsNullable() const { return nullability() == Nullability::kNullable; }
|
||||
|
@ -8462,45 +8475,33 @@ class AbstractType : public Instance {
|
|||
const AbstractType& other_type,
|
||||
TypeEquality kind) const;
|
||||
|
||||
UntaggedAbstractType::TypeState type_state() const {
|
||||
return static_cast<UntaggedAbstractType::TypeState>(
|
||||
UntaggedAbstractType::TypeStateBits::decode(untag()->flags_));
|
||||
}
|
||||
void set_flags(uint32_t value) const;
|
||||
void set_type_state(UntaggedAbstractType::TypeState value) const;
|
||||
void set_nullability(Nullability value) const;
|
||||
|
||||
HEAP_OBJECT_IMPLEMENTATION(AbstractType, Instance);
|
||||
friend class Class;
|
||||
friend class Function;
|
||||
friend class TypeArguments;
|
||||
friend class TypeRef;
|
||||
};
|
||||
|
||||
// A Type consists of a class, possibly parameterized with type
|
||||
// arguments. Example: C<T1, T2>.
|
||||
class Type : public AbstractType {
|
||||
public:
|
||||
static intptr_t type_class_id_offset() {
|
||||
return OFFSET_OF(UntaggedType, type_class_id_);
|
||||
}
|
||||
static intptr_t arguments_offset() {
|
||||
return OFFSET_OF(UntaggedType, arguments_);
|
||||
}
|
||||
static intptr_t type_state_offset() {
|
||||
return OFFSET_OF(UntaggedType, type_state_);
|
||||
}
|
||||
static intptr_t hash_offset() { return OFFSET_OF(UntaggedType, hash_); }
|
||||
static intptr_t nullability_offset() {
|
||||
return OFFSET_OF(UntaggedType, nullability_);
|
||||
}
|
||||
virtual bool IsFinalized() const {
|
||||
return (untag()->type_state_ == UntaggedType::kFinalizedInstantiated) ||
|
||||
(untag()->type_state_ == UntaggedType::kFinalizedUninstantiated);
|
||||
}
|
||||
virtual void SetIsFinalized() const;
|
||||
virtual bool IsBeingFinalized() const {
|
||||
return untag()->type_state_ == UntaggedType::kBeingFinalized;
|
||||
}
|
||||
virtual void SetIsBeingFinalized() const;
|
||||
virtual bool HasTypeClass() const {
|
||||
ASSERT(type_class_id() != kIllegalCid);
|
||||
return true;
|
||||
}
|
||||
virtual Nullability nullability() const {
|
||||
return static_cast<Nullability>(untag()->nullability_);
|
||||
}
|
||||
TypePtr ToNullability(Nullability value, Heap::Space space) const;
|
||||
virtual classid_t type_class_id() const;
|
||||
virtual ClassPtr type_class() const;
|
||||
|
@ -8616,11 +8617,6 @@ class Type : public AbstractType {
|
|||
// in ClassIdTagType. This allows us to guard against that case, instead of
|
||||
// silently truncating the cid.
|
||||
void set_type_class_id(intptr_t id) const;
|
||||
void set_type_state(uint8_t state) const;
|
||||
void set_nullability(Nullability value) const {
|
||||
ASSERT(!IsCanonical());
|
||||
StoreNonPointer(&untag()->nullability_, static_cast<uint8_t>(value));
|
||||
}
|
||||
|
||||
static TypePtr New(Heap::Space space = Heap::kOld);
|
||||
|
||||
|
@ -8648,28 +8644,10 @@ class FunctionType : public AbstractType {
|
|||
using PackedNumOptionalParameters =
|
||||
UntaggedFunctionType::PackedNumOptionalParameters;
|
||||
|
||||
static intptr_t type_state_offset() {
|
||||
return OFFSET_OF(UntaggedFunctionType, type_state_);
|
||||
}
|
||||
static intptr_t hash_offset() {
|
||||
return OFFSET_OF(UntaggedFunctionType, hash_);
|
||||
}
|
||||
static intptr_t nullability_offset() {
|
||||
return OFFSET_OF(UntaggedFunctionType, nullability_);
|
||||
}
|
||||
virtual bool IsFinalized() const {
|
||||
return (untag()->type_state_ == UntaggedType::kFinalizedInstantiated) ||
|
||||
(untag()->type_state_ == UntaggedType::kFinalizedUninstantiated);
|
||||
}
|
||||
virtual void SetIsFinalized() const;
|
||||
virtual bool IsBeingFinalized() const {
|
||||
return untag()->type_state_ == UntaggedType::kBeingFinalized;
|
||||
}
|
||||
virtual void SetIsBeingFinalized() const;
|
||||
virtual bool HasTypeClass() const { return false; }
|
||||
virtual Nullability nullability() const {
|
||||
return static_cast<Nullability>(untag()->nullability_);
|
||||
}
|
||||
FunctionTypePtr ToNullability(Nullability value, Heap::Space space) const;
|
||||
virtual classid_t type_class_id() const { return kIllegalCid; }
|
||||
virtual bool IsInstantiated(Genericity genericity = kAny,
|
||||
|
@ -8919,12 +8897,6 @@ class FunctionType : public AbstractType {
|
|||
private:
|
||||
void SetHash(intptr_t value) const;
|
||||
|
||||
void set_type_state(uint8_t state) const;
|
||||
void set_nullability(Nullability value) const {
|
||||
ASSERT(!IsCanonical());
|
||||
StoreNonPointer(&untag()->nullability_, static_cast<uint8_t>(value));
|
||||
}
|
||||
|
||||
static FunctionTypePtr New(Heap::Space space);
|
||||
|
||||
FINAL_HEAP_OBJECT_IMPLEMENTATION(FunctionType, AbstractType);
|
||||
|
@ -8938,26 +8910,8 @@ class FunctionType : public AbstractType {
|
|||
// names of the named fields.
|
||||
class RecordType : public AbstractType {
|
||||
public:
|
||||
static intptr_t type_state_offset() {
|
||||
return OFFSET_OF(UntaggedRecordType, type_state_);
|
||||
}
|
||||
static intptr_t hash_offset() { return OFFSET_OF(UntaggedRecordType, hash_); }
|
||||
static intptr_t nullability_offset() {
|
||||
return OFFSET_OF(UntaggedRecordType, nullability_);
|
||||
}
|
||||
virtual bool IsFinalized() const {
|
||||
return (untag()->type_state_ == UntaggedType::kFinalizedInstantiated) ||
|
||||
(untag()->type_state_ == UntaggedType::kFinalizedUninstantiated);
|
||||
}
|
||||
virtual void SetIsFinalized() const;
|
||||
virtual bool IsBeingFinalized() const {
|
||||
return untag()->type_state_ == UntaggedType::kBeingFinalized;
|
||||
}
|
||||
virtual void SetIsBeingFinalized() const;
|
||||
virtual bool HasTypeClass() const { return false; }
|
||||
virtual Nullability nullability() const {
|
||||
return static_cast<Nullability>(untag()->nullability_);
|
||||
}
|
||||
RecordTypePtr ToNullability(Nullability value, Heap::Space space) const;
|
||||
virtual classid_t type_class_id() const { return kIllegalCid; }
|
||||
virtual bool IsInstantiated(Genericity genericity = kAny,
|
||||
|
@ -9021,11 +8975,6 @@ class RecordType : public AbstractType {
|
|||
private:
|
||||
void SetHash(intptr_t value) const;
|
||||
|
||||
void set_type_state(uint8_t state) const;
|
||||
void set_nullability(Nullability value) const {
|
||||
ASSERT(!IsCanonical());
|
||||
StoreNonPointer(&untag()->nullability_, static_cast<uint8_t>(value));
|
||||
}
|
||||
void set_field_types(const Array& value) const;
|
||||
void set_field_names(const Array& value) const;
|
||||
|
||||
|
@ -9046,19 +8995,6 @@ class TypeRef : public AbstractType {
|
|||
public:
|
||||
static intptr_t type_offset() { return OFFSET_OF(UntaggedTypeRef, type_); }
|
||||
|
||||
virtual bool IsFinalized() const {
|
||||
const AbstractType& ref_type = AbstractType::Handle(type());
|
||||
return !ref_type.IsNull() && ref_type.IsFinalized();
|
||||
}
|
||||
virtual bool IsBeingFinalized() const {
|
||||
const AbstractType& ref_type = AbstractType::Handle(type());
|
||||
return ref_type.IsNull() || ref_type.IsBeingFinalized();
|
||||
}
|
||||
virtual Nullability nullability() const {
|
||||
const AbstractType& ref_type = AbstractType::Handle(type());
|
||||
ASSERT(!ref_type.IsNull());
|
||||
return ref_type.nullability();
|
||||
}
|
||||
virtual bool HasTypeClass() const {
|
||||
return (type() != AbstractType::null()) &&
|
||||
AbstractType::Handle(type()).HasTypeClass();
|
||||
|
@ -9123,23 +9059,6 @@ class TypeRef : public AbstractType {
|
|||
// to the ObjectType.
|
||||
class TypeParameter : public AbstractType {
|
||||
public:
|
||||
virtual bool IsFinalized() const {
|
||||
return UntaggedTypeParameter::FinalizedBit::decode(untag()->flags_);
|
||||
}
|
||||
virtual void SetIsFinalized() const;
|
||||
virtual bool IsBeingFinalized() const {
|
||||
return UntaggedTypeParameter::BeingFinalizedBit::decode(untag()->flags_);
|
||||
}
|
||||
virtual void SetIsBeingFinalized() const;
|
||||
static intptr_t flags_offset() {
|
||||
return OFFSET_OF(UntaggedTypeParameter, flags_);
|
||||
}
|
||||
static intptr_t nullability_offset() {
|
||||
return OFFSET_OF(UntaggedTypeParameter, nullability_);
|
||||
}
|
||||
virtual Nullability nullability() const {
|
||||
return static_cast<Nullability>(untag()->nullability_);
|
||||
}
|
||||
TypeParameterPtr ToNullability(Nullability value, Heap::Space space) const;
|
||||
virtual bool HasTypeClass() const { return false; }
|
||||
virtual classid_t type_class_id() const { return kIllegalCid; }
|
||||
|
@ -9232,8 +9151,6 @@ class TypeParameter : public AbstractType {
|
|||
|
||||
void set_parameterized_class(const Class& value) const;
|
||||
void set_name(const String& value) const;
|
||||
void set_flags(uint8_t flags) const;
|
||||
void set_nullability(Nullability value) const;
|
||||
|
||||
static TypeParameterPtr New();
|
||||
|
||||
|
|
|
@ -2607,26 +2607,29 @@ class UntaggedTypeParameters : public UntaggedObject {
|
|||
};
|
||||
|
||||
class UntaggedAbstractType : public UntaggedInstance {
|
||||
protected:
|
||||
// Accessed from generated code.
|
||||
std::atomic<uword> type_test_stub_entry_point_;
|
||||
// Accessed from generated code.
|
||||
uint32_t flags_;
|
||||
COMPRESSED_POINTER_FIELD(CodePtr, type_test_stub)
|
||||
VISIT_FROM(type_test_stub)
|
||||
|
||||
public:
|
||||
enum TypeState {
|
||||
kAllocated, // Initial state.
|
||||
kBeingFinalized, // In the process of being finalized.
|
||||
kFinalizedInstantiated, // Instantiated type ready for use.
|
||||
kFinalizedUninstantiated, // Uninstantiated type ready for use.
|
||||
// Adjust kTypeStateBitSize if more are added.
|
||||
};
|
||||
|
||||
protected:
|
||||
static constexpr intptr_t kTypeStateBitSize = 2;
|
||||
COMPILE_ASSERT(sizeof(std::atomic<word>) == sizeof(word));
|
||||
using NullabilityBits = BitField<decltype(flags_), uint8_t, 0, 2>;
|
||||
static constexpr intptr_t kNullabilityMask = NullabilityBits::mask();
|
||||
|
||||
// Accessed from generated code.
|
||||
std::atomic<uword> type_test_stub_entry_point_;
|
||||
#if defined(DART_COMPRESSED_POINTERS)
|
||||
uint32_t padding_; // Makes Windows and Posix agree on layout.
|
||||
#endif
|
||||
COMPRESSED_POINTER_FIELD(CodePtr, type_test_stub)
|
||||
VISIT_FROM(type_test_stub)
|
||||
static constexpr intptr_t kTypeStateShift = NullabilityBits::kNextBit;
|
||||
static constexpr intptr_t kTypeStateBits = 2;
|
||||
using TypeStateBits =
|
||||
BitField<decltype(flags_), uint8_t, kTypeStateShift, kTypeStateBits>;
|
||||
|
||||
private:
|
||||
RAW_HEAP_OBJECT_IMPLEMENTATION(AbstractType);
|
||||
|
@ -2636,18 +2639,29 @@ class UntaggedAbstractType : public UntaggedInstance {
|
|||
};
|
||||
|
||||
class UntaggedType : public UntaggedAbstractType {
|
||||
public:
|
||||
static constexpr intptr_t kTypeClassIdShift = TypeStateBits::kNextBit;
|
||||
using TypeClassIdBits = BitField<decltype(flags_),
|
||||
ClassIdTagType,
|
||||
kTypeClassIdShift,
|
||||
sizeof(ClassIdTagType) * kBitsPerByte>;
|
||||
|
||||
private:
|
||||
RAW_HEAP_OBJECT_IMPLEMENTATION(Type);
|
||||
|
||||
COMPRESSED_POINTER_FIELD(TypeArgumentsPtr, arguments)
|
||||
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
|
||||
VISIT_TO(hash)
|
||||
ClassIdTagType type_class_id_;
|
||||
uint8_t type_state_;
|
||||
uint8_t nullability_;
|
||||
|
||||
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
|
||||
|
||||
ClassIdTagType type_class_id() const {
|
||||
return TypeClassIdBits::decode(flags_);
|
||||
}
|
||||
void set_type_class_id(ClassIdTagType value) {
|
||||
flags_ = TypeClassIdBits::update(value, flags_);
|
||||
}
|
||||
|
||||
friend class compiler::target::UntaggedType;
|
||||
friend class CidRewriteVisitor;
|
||||
friend class UntaggedTypeArguments;
|
||||
|
@ -2665,8 +2679,6 @@ class UntaggedFunctionType : public UntaggedAbstractType {
|
|||
VISIT_TO(hash)
|
||||
AtomicBitFieldContainer<uint32_t> packed_parameter_counts_;
|
||||
AtomicBitFieldContainer<uint16_t> packed_type_parameter_counts_;
|
||||
uint8_t type_state_;
|
||||
uint8_t nullability_;
|
||||
|
||||
// The bit fields are public for use in kernel_to_il.cc.
|
||||
public:
|
||||
|
@ -2716,8 +2728,6 @@ class UntaggedRecordType : public UntaggedAbstractType {
|
|||
COMPRESSED_POINTER_FIELD(ArrayPtr, field_names);
|
||||
COMPRESSED_POINTER_FIELD(SmiPtr, hash)
|
||||
VISIT_TO(hash)
|
||||
uint8_t type_state_;
|
||||
uint8_t nullability_;
|
||||
|
||||
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
|
||||
};
|
||||
|
@ -2742,14 +2752,6 @@ class UntaggedTypeParameter : public UntaggedAbstractType {
|
|||
ClassIdTagType parameterized_class_id_; // Or kFunctionCid for function tp.
|
||||
uint8_t base_; // Number of enclosing function type parameters.
|
||||
uint8_t index_; // Keep size in sync with BuildTypeParameterTypeTestStub.
|
||||
uint8_t flags_;
|
||||
uint8_t nullability_;
|
||||
|
||||
public:
|
||||
using BeingFinalizedBit = BitField<decltype(flags_), bool, 0, 1>;
|
||||
using FinalizedBit =
|
||||
BitField<decltype(flags_), bool, BeingFinalizedBit::kNextBit, 1>;
|
||||
static constexpr intptr_t kFlagsBitSize = FinalizedBit::kNextBit;
|
||||
|
||||
private:
|
||||
CompressedObjectPtr* to_snapshot(Snapshot::Kind kind) { return to(); }
|
||||
|
|
|
@ -135,7 +135,6 @@ namespace dart {
|
|||
F(TypeArguments, nullability_) \
|
||||
F(AbstractType, type_test_stub_) \
|
||||
F(Type, type_test_stub_) \
|
||||
F(Type, type_class_id_) \
|
||||
F(Type, arguments_) \
|
||||
F(Type, hash_) \
|
||||
F(FunctionType, type_test_stub_) \
|
||||
|
|
|
@ -1066,22 +1066,26 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck(
|
|||
if (strict_null_safety) {
|
||||
__ BranchIf(NOT_EQUAL, &check_subtype_type_class_ids);
|
||||
// If non-nullable Object, then the subtype must be legacy or non-nullable.
|
||||
__ CompareTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSuperTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
static_cast<int8_t>(Nullability::kNonNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(NOT_EQUAL, &is_subtype);
|
||||
__ Comment("Checking for legacy or non-nullable instance type argument");
|
||||
compiler::Label subtype_is_type;
|
||||
UnwrapAbstractType(assembler, TTSInternalRegs::kSubTypeArgumentReg,
|
||||
TTSInternalRegs::kScratchReg, &subtype_is_type);
|
||||
__ CompareFunctionTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSubTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNullable));
|
||||
static_cast<int8_t>(Nullability::kNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
__ Jump(&is_subtype);
|
||||
__ Bind(&subtype_is_type);
|
||||
__ CompareTypeNullabilityWith(TTSInternalRegs::kSubTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNullable));
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSubTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
__ Jump(&is_subtype);
|
||||
} else {
|
||||
|
@ -1107,15 +1111,17 @@ void TypeTestingStubGenerator::BuildOptimizedTypeParameterArgumentValueCheck(
|
|||
compiler::Label supertype_is_type;
|
||||
UnwrapAbstractType(assembler, TTSInternalRegs::kSuperTypeArgumentReg,
|
||||
TTSInternalRegs::kScratchReg, &supertype_is_type);
|
||||
__ CompareFunctionTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSuperTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
static_cast<int8_t>(Nullability::kNonNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
__ Jump(&is_subtype, compiler::Assembler::kNearJump);
|
||||
__ Bind(&supertype_is_type);
|
||||
__ CompareTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSuperTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNonNullable));
|
||||
static_cast<int8_t>(Nullability::kNonNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
}
|
||||
|
||||
|
@ -1165,9 +1171,10 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck(
|
|||
if (type.IsObjectType() || type.IsDartFunctionType()) {
|
||||
if (strict_null_safety && type.IsNonNullable()) {
|
||||
// Nullable types cannot be a subtype of a non-nullable type.
|
||||
__ CompareFunctionTypeNullabilityWith(
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSubTypeArgumentReg,
|
||||
compiler::target::Nullability::kNullable);
|
||||
static_cast<int8_t>(Nullability::kNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
}
|
||||
// No further checks needed for non-nullable Object or Function.
|
||||
|
@ -1183,8 +1190,10 @@ void TypeTestingStubGenerator::BuildOptimizedTypeArgumentValueCheck(
|
|||
__ Bind(&sub_is_type);
|
||||
if (strict_null_safety && type.IsNonNullable()) {
|
||||
// Nullable types cannot be a subtype of a non-nullable type in strict mode.
|
||||
__ CompareTypeNullabilityWith(TTSInternalRegs::kSubTypeArgumentReg,
|
||||
compiler::target::Nullability::kNullable);
|
||||
__ CompareAbstractTypeNullabilityWith(
|
||||
TTSInternalRegs::kSubTypeArgumentReg,
|
||||
static_cast<int8_t>(Nullability::kNullable),
|
||||
TTSInternalRegs::kScratchReg);
|
||||
__ BranchIf(EQUAL, check_failed);
|
||||
// Fall through to bottom type checks.
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue