diff --git a/runtime/vm/compiler/assembler/assembler_base.cc b/runtime/vm/compiler/assembler/assembler_base.cc index 82a9c9351cc..95540de65b4 100644 --- a/runtime/vm/compiler/assembler/assembler_base.cc +++ b/runtime/vm/compiler/assembler/assembler_base.cc @@ -37,7 +37,7 @@ void AssemblerBase::LoadFromSlot(Register dst, return LoadFromOffset(dst, address, sz); } if (slot.is_compressed()) { - if (slot.ComputeCompileType().ToCid() == kSmiCid) { + if (slot.type().ToCid() == kSmiCid) { return LoadCompressedSmi(dst, address); } else { return LoadCompressedField(dst, address); @@ -56,11 +56,11 @@ void AssemblerBase::StoreToSlot(Register src, Register base, const Slot& slot) { if (slot.is_compressed()) { return StoreCompressedIntoObject( base, address, src, - slot.ComputeCompileType().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); + slot.type().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); } return StoreIntoObject( base, address, src, - slot.ComputeCompileType().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); + slot.type().CanBeSmi() ? kValueCanBeSmi : kValueIsNotSmi); } void AssemblerBase::StoreToSlotNoBarrier(Register src, diff --git a/runtime/vm/compiler/backend/compile_type.h b/runtime/vm/compiler/backend/compile_type.h index bc9c6e5ee6e..b81255226f2 100644 --- a/runtime/vm/compiler/backend/compile_type.h +++ b/runtime/vm/compiler/backend/compile_type.h @@ -11,6 +11,7 @@ #include "vm/allocation.h" #include "vm/class_id.h" +#include "vm/compiler/backend/locations.h" #include "vm/compiler/runtime_api.h" namespace dart { @@ -137,6 +138,11 @@ class CompileType : public ZoneAllocated { // kSentinelCid. static CompileType FromCid(intptr_t cid); + // Create a new CompileType representing an unboxed value + // with given unboxed representation. + // Resulting CompileType cannot be null and cannot be sentinel. + static CompileType FromUnboxedRepresentation(Representation rep); + // Create None CompileType. It is the bottom of the lattice and is used to // represent type of the phi that was not yet inferred. static CompileType None() { diff --git a/runtime/vm/compiler/backend/il_serializer.cc b/runtime/vm/compiler/backend/il_serializer.cc index a6decafa4a6..2bd862c15f0 100644 --- a/runtime/vm/compiler/backend/il_serializer.cc +++ b/runtime/vm/compiler/backend/il_serializer.cc @@ -2331,7 +2331,7 @@ void Slot::Write(FlowGraphSerializer* s) const { s->Write(flags_); s->Write(offset_in_bytes_); s->Write(*DataAs()); - s->Write(*static_type_); + type_.Write(s); break; case Kind::kDartField: s->Write(field()); @@ -2344,18 +2344,17 @@ void Slot::Write(FlowGraphSerializer* s) const { const Slot& Slot::Read(FlowGraphDeserializer* d) { const Kind kind = static_cast(d->Read>()); int8_t flags = 0; - ClassIdTagType cid = kDynamicCid; intptr_t offset = -1; const void* data = nullptr; - const AbstractType* static_type = nullptr; + CompileType type = CompileType::None(); Representation representation = kTagged; switch (kind) { case Kind::kTypeArguments: flags = d->Read(); offset = d->Read(); - cid = kTypeArgumentsCid; data = ":type_arguments"; + type = CompileType::FromCid(kTypeArgumentsCid); break; case Kind::kTypeArgumentsIndex: flags = @@ -2363,24 +2362,26 @@ const Slot& Slot::Read(FlowGraphDeserializer* d) { IsCompressedBit::encode(TypeArguments::ContainsCompressedPointers()); offset = d->Read(); data = ":argument"; + type = CompileType(CompileType::kCannotBeNull, + CompileType::kCannotBeSentinel, kDynamicCid, nullptr); break; case Kind::kArrayElement: - flags = IsNullableBit::encode(true) | - IsCompressedBit::encode(Array::ContainsCompressedPointers()); + flags = IsCompressedBit::encode(Array::ContainsCompressedPointers()); offset = d->Read(); data = ":array_element"; + type = CompileType::Dynamic(); break; case Kind::kRecordField: - flags = IsNullableBit::encode(true) | - IsCompressedBit::encode(Record::ContainsCompressedPointers()); + flags = IsCompressedBit::encode(Record::ContainsCompressedPointers()); offset = d->Read(); data = ":record_field"; + type = CompileType::Dynamic(); break; case Kind::kCapturedVariable: flags = d->Read(); offset = d->Read(); data = &d->Read(); - static_type = &d->Read(); + type = CompileType(d); break; case Kind::kDartField: { const Field& field = d->Read(); @@ -2390,8 +2391,8 @@ const Slot& Slot::Read(FlowGraphDeserializer* d) { return Slot::GetNativeSlot(kind); } - return GetCanonicalSlot(d->thread(), kind, flags, cid, offset, data, - static_type, representation); + return GetCanonicalSlot(d->thread(), kind, flags, offset, data, type, + representation); } template <> diff --git a/runtime/vm/compiler/backend/il_test.cc b/runtime/vm/compiler/backend/il_test.cc index 7a21dbd93ab..5bffa9b4f34 100644 --- a/runtime/vm/compiler/backend/il_test.cc +++ b/runtime/vm/compiler/backend/il_test.cc @@ -1320,8 +1320,15 @@ ISOLATE_UNIT_TEST_CASE(IL_Canonicalize_RepresentationChange) { TestRepresentationChangeDuringCanonicalization(thread, false); } -static void TestCanonicalizationOfTypedDataViewFieldLoads(Thread* thread, - const Slot& field) { +enum TypeDataField { + TypedDataBase_length, + TypedDataView_offset_in_bytes, + TypedDataView_typed_data, +}; + +static void TestCanonicalizationOfTypedDataViewFieldLoads( + Thread* thread, + TypeDataField field_kind) { const auto& typed_data_lib = Library::Handle(Library::TypedDataLibrary()); const auto& view_cls = Class::Handle( typed_data_lib.LookupClassAllowPrivate(Symbols::_Float32ArrayView())); @@ -1336,6 +1343,19 @@ static void TestCanonicalizationOfTypedDataViewFieldLoads(Thread* thread, CompilerState S(thread, /*is_aot=*/false, /*is_optimizing=*/true); FlowGraphBuilderHelper H; + const Slot* field = nullptr; + switch (field_kind) { + case TypedDataBase_length: + field = &Slot::TypedDataBase_length(); + break; + case TypedDataView_offset_in_bytes: + field = &Slot::TypedDataView_offset_in_bytes(); + break; + case TypedDataView_typed_data: + field = &Slot::TypedDataView_typed_data(); + break; + } + auto b1 = H.flow_graph()->graph_entry()->normal_entry(); const auto constant_4 = H.IntConstant(4); @@ -1359,29 +1379,32 @@ static void TestCanonicalizationOfTypedDataViewFieldLoads(Thread* thread, DeoptId::kNone, 1, ICData::RebindRule::kStatic)); // array_alias <- LoadField(view.length) load = builder.AddDefinition( - new LoadFieldInstr(new Value(view), field, InstructionSource())); + new LoadFieldInstr(new Value(view), *field, InstructionSource())); // Return(load) ret = builder.AddReturn(new Value(load)); } H.FinishGraph(); H.flow_graph()->Canonicalize(); - if (field.IsIdentical(Slot::TypedDataBase_length())) { - EXPECT_PROPERTY(ret->value()->definition(), &it == constant_1); - } else if (field.IsIdentical(Slot::TypedDataView_offset_in_bytes())) { - EXPECT_PROPERTY(ret->value()->definition(), &it == constant_4); - } else if (field.IsIdentical(Slot::TypedDataView_typed_data())) { - EXPECT_PROPERTY(ret->value()->definition(), &it == array); + switch (field_kind) { + case TypedDataBase_length: + EXPECT_PROPERTY(ret->value()->definition(), &it == constant_1); + break; + case TypedDataView_offset_in_bytes: + EXPECT_PROPERTY(ret->value()->definition(), &it == constant_4); + break; + case TypedDataView_typed_data: + EXPECT_PROPERTY(ret->value()->definition(), &it == array); + break; } } ISOLATE_UNIT_TEST_CASE(IL_Canonicalize_TypedDataViewFactory) { + TestCanonicalizationOfTypedDataViewFieldLoads(thread, TypedDataBase_length); TestCanonicalizationOfTypedDataViewFieldLoads(thread, - Slot::TypedDataBase_length()); - TestCanonicalizationOfTypedDataViewFieldLoads( - thread, Slot::TypedDataView_offset_in_bytes()); - TestCanonicalizationOfTypedDataViewFieldLoads( - thread, Slot::TypedDataView_typed_data()); + TypedDataView_offset_in_bytes); + TestCanonicalizationOfTypedDataViewFieldLoads(thread, + TypedDataView_typed_data); } // Check that canonicalize can devirtualize InstanceCall based on type diff --git a/runtime/vm/compiler/backend/slot.cc b/runtime/vm/compiler/backend/slot.cc index d40eac1b496..cb793dd4a44 100644 --- a/runtime/vm/compiler/backend/slot.cc +++ b/runtime/vm/compiler/backend/slot.cc @@ -13,6 +13,13 @@ namespace dart { +enum NativeSlotsEnumeration { +#define DECLARE_KIND(CN, __, FN, ___, ____) k##CN##_##FN, + NATIVE_SLOTS_LIST(DECLARE_KIND) +#undef DECLARE_KIND + kNativeSlotsCount +}; + // Canonicalization cache for Slot objects. // // This cache is attached to the CompilerState to ensure that we preserve @@ -38,96 +45,90 @@ class SlotCache : public ZoneAllocated { return *result; } + const Slot& GetNativeSlot(Slot::Kind kind) { + const intptr_t index = static_cast(kind); + ASSERT((index >= 0) && (index < kNativeSlotsCount)); + const Slot* slot = native_fields_[index]; + if (slot == nullptr) { + native_fields_[index] = slot = CreateNativeSlot(kind); + } + return *slot; + } + private: explicit SlotCache(Thread* thread) : zone_(thread->zone()), fields_(thread->zone()) {} + Slot* CreateNativeSlot(Slot::Kind kind); + Zone* const zone_; PointerSet fields_; + const Slot* native_fields_[kNativeSlotsCount] = {nullptr}; }; -static classid_t GetUnboxedNativeSlotCid(Representation rep) { - // Currently we only support integer unboxed fields. - if (RepresentationUtils::IsUnboxedInteger(rep)) { - return Boxing::BoxCid(rep); - } - UNREACHABLE(); - return kIllegalCid; -} - -AcqRelAtomic Slot::native_fields_(nullptr); - -enum NativeSlotsEnumeration { -#define DECLARE_KIND(CN, __, FN, ___, ____) k##CN##_##FN, - NATIVE_SLOTS_LIST(DECLARE_KIND) -#undef DECLARE_KIND - kNativeSlotsCount -}; - -const Slot& Slot::GetNativeSlot(Kind kind) { - if (native_fields_.load() == nullptr) { - Slot* new_value = new Slot[kNativeSlotsCount]{ -#define NULLABLE_FIELD_FINAL(ClassName) \ - (IsNullableBit::encode(true) | IsImmutableBit::encode(true) | \ - IsCompressedBit::encode(ClassName::ContainsCompressedPointers())) -#define NULLABLE_FIELD_VAR(ClassName) \ - (IsNullableBit::encode(true) | \ - IsCompressedBit::encode(ClassName::ContainsCompressedPointers())) +Slot* SlotCache::CreateNativeSlot(Slot::Kind kind) { + switch (kind) { +#define FIELD_FINAL true +#define FIELD_VAR false #define DEFINE_NULLABLE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, \ FieldName, cid, mutability) \ - Slot(Kind::k##ClassName##_##FieldName, \ - NULLABLE_FIELD_##mutability(ClassName), k##cid##Cid, \ - compiler::target::ClassName::FieldName##_offset(), \ - #ClassName "." #FieldName, nullptr, kTagged), + case Slot::Kind::k##ClassName##_##FieldName: \ + return new (zone_) Slot( \ + Slot::Kind::k##ClassName##_##FieldName, \ + (Slot::IsImmutableBit::encode(FIELD_##mutability) | \ + Slot::IsCompressedBit::encode( \ + ClassName::ContainsCompressedPointers())), \ + compiler::target::ClassName::FieldName##_offset(), \ + #ClassName "." #FieldName, \ + CompileType(CompileType::kCanBeNull, CompileType::kCannotBeSentinel, \ + k##cid##Cid, nullptr), \ + kTagged); - NULLABLE_BOXED_NATIVE_SLOTS_LIST(DEFINE_NULLABLE_BOXED_NATIVE_FIELD) + NULLABLE_BOXED_NATIVE_SLOTS_LIST(DEFINE_NULLABLE_BOXED_NATIVE_FIELD) #undef DEFINE_NULLABLE_BOXED_NATIVE_FIELD -#undef NULLABLE_FIELD_FINAL -#undef NULLABLE_FIELD_VAR -#define NONNULLABLE_FIELD_FINAL(ClassName) \ - (Slot::IsImmutableBit::encode(true) | \ - IsCompressedBit::encode(ClassName::ContainsCompressedPointers())) -#define NONNULLABLE_FIELD_VAR(ClassName) \ - (IsCompressedBit::encode(ClassName::ContainsCompressedPointers())) #define DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD(ClassName, UnderlyingType, \ FieldName, cid, mutability) \ - Slot(Kind::k##ClassName##_##FieldName, \ - NONNULLABLE_FIELD_##mutability(ClassName), k##cid##Cid, \ - compiler::target::ClassName::FieldName##_offset(), \ - #ClassName "." #FieldName, nullptr, kTagged), + case Slot::Kind::k##ClassName##_##FieldName: \ + return new (zone_) Slot( \ + Slot::Kind::k##ClassName##_##FieldName, \ + (Slot::IsImmutableBit::encode(FIELD_##mutability) | \ + Slot::IsCompressedBit::encode( \ + ClassName::ContainsCompressedPointers())), \ + compiler::target::ClassName::FieldName##_offset(), \ + #ClassName "." #FieldName, \ + CompileType(CompileType::kCannotBeNull, \ + CompileType::kCannotBeSentinel, k##cid##Cid, nullptr), \ + kTagged); - NONNULLABLE_BOXED_NATIVE_SLOTS_LIST( - DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD) + NONNULLABLE_BOXED_NATIVE_SLOTS_LIST(DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD) #undef DEFINE_NONNULLABLE_BOXED_NATIVE_FIELD -#undef NONNULLABLE_FIELD_VAR -#undef NONNULLABLE_FIELD_FINAL -#define UNBOXED_FIELD_FINAL (Slot::IsImmutableBit::encode(true)) -#define UNBOXED_FIELD_VAR (0) #define DEFINE_UNBOXED_NATIVE_FIELD(ClassName, UnderlyingType, FieldName, \ representation, mutability) \ - Slot(Kind::k##ClassName##_##FieldName, UNBOXED_FIELD_##mutability, \ - GetUnboxedNativeSlotCid(kUnboxed##representation), \ - compiler::target::ClassName::FieldName##_offset(), \ - #ClassName "." #FieldName, nullptr, kUnboxed##representation), + case Slot::Kind::k##ClassName##_##FieldName: \ + return new (zone_) \ + Slot(Slot::Kind::k##ClassName##_##FieldName, \ + Slot::IsImmutableBit::encode(FIELD_##mutability), \ + compiler::target::ClassName::FieldName##_offset(), \ + #ClassName "." #FieldName, \ + CompileType::FromUnboxedRepresentation(kUnboxed##representation), \ + kUnboxed##representation); - UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD) + UNBOXED_NATIVE_SLOTS_LIST(DEFINE_UNBOXED_NATIVE_FIELD) #undef DEFINE_UNBOXED_NATIVE_FIELD -#undef UNBOXED_FIELD_VAR -#undef UNBOXED_FIELD_FINAL - }; - Slot* old_value = nullptr; - if (!native_fields_.compare_exchange_strong(old_value, new_value)) { - delete[] new_value; - } +#undef FIELD_VAR +#undef FIELD_FINAL + default: + UNREACHABLE(); } +} - ASSERT(static_cast(kind) < kNativeSlotsCount); - return native_fields_.load()[static_cast(kind)]; +const Slot& Slot::GetNativeSlot(Kind kind) { + return SlotCache::Instance(Thread::Current()).GetNativeSlot(kind); } bool Slot::IsImmutableLengthSlot() const { @@ -256,8 +257,8 @@ const Slot& Slot::GetTypeArgumentsSlotFor(Thread* thread, const Class& cls) { IsImmutableBit::encode(true) | IsCompressedBit::encode( compiler::target::Class::HasCompressedPointers(cls)), - kTypeArgumentsCid, offset, ":type_arguments", - /*static_type=*/nullptr, kTagged); + offset, ":type_arguments", CompileType::FromCid(kTypeArgumentsCid), + kTagged); } const Slot& Slot::GetContextVariableSlotFor(Thread* thread, @@ -266,12 +267,12 @@ const Slot& Slot::GetContextVariableSlotFor(Thread* thread, return GetCanonicalSlot( thread, Kind::kCapturedVariable, IsImmutableBit::encode(variable.is_final() && !variable.is_late()) | - IsNullableBit::encode(true) | - IsCompressedBit::encode(Context::ContainsCompressedPointers()) | - IsSentinelVisibleBit::encode(variable.is_late()), - kDynamicCid, + IsCompressedBit::encode(Context::ContainsCompressedPointers()), compiler::target::Context::variable_offset(variable.index().value()), - &variable.name(), &variable.type(), kTagged); + &variable.name(), + CompileType::FromAbstractType(variable.type(), CompileType::kCanBeNull, + variable.is_late()), + kTagged); } const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) { @@ -281,38 +282,36 @@ const Slot& Slot::GetTypeArgumentsIndexSlot(Thread* thread, intptr_t index) { thread, Kind::kTypeArgumentsIndex, IsImmutableBit::encode(true) | IsCompressedBit::encode(TypeArguments::ContainsCompressedPointers()), - kDynamicCid, offset, ":argument", /*static_type=*/nullptr, kTagged); + offset, ":argument", + CompileType(CompileType::kCannotBeNull, CompileType::kCannotBeSentinel, + kDynamicCid, nullptr), + kTagged); } const Slot& Slot::GetArrayElementSlot(Thread* thread, intptr_t offset_in_bytes) { return GetCanonicalSlot( thread, Kind::kArrayElement, - IsNullableBit::encode(true) | - IsCompressedBit::encode(Array::ContainsCompressedPointers()), - kDynamicCid, offset_in_bytes, ":array_element", - /*static_type=*/nullptr, kTagged); + IsCompressedBit::encode(Array::ContainsCompressedPointers()), + offset_in_bytes, ":array_element", CompileType::Dynamic(), kTagged); } const Slot& Slot::GetRecordFieldSlot(Thread* thread, intptr_t offset_in_bytes) { return GetCanonicalSlot( thread, Kind::kRecordField, - IsNullableBit::encode(true) | - IsCompressedBit::encode(Record::ContainsCompressedPointers()), - kDynamicCid, offset_in_bytes, ":record_field", - /*static_type=*/nullptr, kTagged); + IsCompressedBit::encode(Record::ContainsCompressedPointers()), + offset_in_bytes, ":record_field", CompileType::Dynamic(), kTagged); } const Slot& Slot::GetCanonicalSlot(Thread* thread, Slot::Kind kind, int8_t flags, - ClassIdTagType cid, intptr_t offset_in_bytes, const void* data, - const AbstractType* static_type, + CompileType type, Representation representation, const FieldGuardState& field_guard_state) { - const Slot& slot = Slot(kind, flags, cid, offset_in_bytes, data, static_type, + const Slot& slot = Slot(kind, flags, offset_in_bytes, data, type, representation, field_guard_state); return SlotCache::Instance(thread).Canonicalize(slot); } @@ -352,8 +351,8 @@ const Slot& Slot::Get(const Field& field, } } - AbstractType& type = AbstractType::ZoneHandle(zone, field.type()); - if (type.IsStrictlyNonNullable()) { + AbstractType& field_type = AbstractType::ZoneHandle(zone, field.type()); + if (field_type.IsStrictlyNonNullable()) { is_nullable = false; } @@ -380,7 +379,7 @@ const Slot& Slot::Get(const Field& field, if (needs_load_guard) { // Should be kept in sync with LoadStaticFieldInstr::ComputeType. - type = Type::DynamicType(); + field_type = Type::DynamicType(); nullable_cid = kDynamicCid; is_nullable = true; used_guarded_state = false; @@ -409,20 +408,25 @@ const Slot& Slot::Get(const Field& field, } } + const bool is_sentinel_visible = + field.is_late() && field.is_final() && !field.has_initializer(); + + CompileType type = (rep != kTagged) + ? CompileType::FromUnboxedRepresentation(rep) + : CompileType(is_nullable, is_sentinel_visible, + nullable_cid, &field_type); + Class& owner = Class::Handle(zone, field.Owner()); const Slot& slot = GetCanonicalSlot( thread, Kind::kDartField, IsImmutableBit::encode((field.is_final() && !field.is_late()) || field.is_const()) | - IsNullableBit::encode(is_nullable) | IsGuardedBit::encode(used_guarded_state) | IsCompressedBit::encode( compiler::target::Class::HasCompressedPointers(owner)) | - IsSentinelVisibleBit::encode(field.is_late() && field.is_final() && - !field.has_initializer()) | IsUnboxedBit::encode(is_unboxed), - nullable_cid, compiler::target::Field::OffsetOf(field), &field, &type, - rep, field_guard_state); + compiler::target::Field::OffsetOf(field), &field, type, rep, + field_guard_state); // If properties of this slot were based on the guarded state make sure // to add the field to the list of guarded fields. Note that during background @@ -451,46 +455,6 @@ const Slot& Slot::Get(const Field& field, return slot; } -CompileType Slot::ComputeCompileType() const { - // If we unboxed the slot, we may know a more precise type. - switch (representation()) { -#if defined(TARGET_ARCH_IS_32_BIT) - // Int32/Uint32 values are not guaranteed to fit in a Smi. - case kUnboxedInt32: - case kUnboxedUint32: -#endif - case kUnboxedInt64: - if (nullable_cid() == kDynamicCid) { - return CompileType::Int(); - } - break; -#if defined(TARGET_ARCH_IS_64_BIT) - // Int32/Uint32 values are guaranteed to fit in a Smi. - case kUnboxedInt32: - case kUnboxedUint32: -#endif - case kUnboxedUint8: - return CompileType::Smi(); - case kUnboxedDouble: - return CompileType::FromCid(kDoubleCid); - case kUnboxedInt32x4: - return CompileType::FromCid(kInt32x4Cid); - case kUnboxedFloat32x4: - return CompileType::FromCid(kFloat32x4Cid); - case kUnboxedFloat64x2: - return CompileType::FromCid(kFloat64x2Cid); - default: - break; - } - - return CompileType(is_nullable(), is_sentinel_visible(), nullable_cid(), - static_type_); -} - -const AbstractType& Slot::static_type() const { - return static_type_ != nullptr ? *static_type_ : Object::null_abstract_type(); -} - const char* Slot::Name() const { if (IsLocalVariable()) { return DataAs()->ToCString(); @@ -513,11 +477,13 @@ bool Slot::Equals(const Slot& other) const { case Kind::kRecordField: return true; - case Kind::kCapturedVariable: + case Kind::kCapturedVariable: { + auto other_type = other.type(); return (flags_ == other.flags_) && (DataAs()->ptr() == other.DataAs()->ptr()) && - static_type_->Equals(*(other.static_type_)); + type().IsEqualTo(&other_type); + } case Kind::kDartField: return other.DataAs()->Original() == diff --git a/runtime/vm/compiler/backend/slot.h b/runtime/vm/compiler/backend/slot.h index c7090831dff..a5e49f0a1a0 100644 --- a/runtime/vm/compiler/backend/slot.h +++ b/runtime/vm/compiler/backend/slot.h @@ -311,28 +311,14 @@ class Slot : public ZoneAllocated { bool is_immutable() const { return IsImmutableBit::decode(flags_); } - intptr_t nullable_cid() const { return cid_; } - bool is_nullable() const { return IsNullableBit::decode(flags_); } - // Returns true if properties of this slot were based on the guarded state // of the corresponding Dart field. bool is_guarded_field() const { return IsGuardedBit::decode(flags_); } bool is_compressed() const { return IsCompressedBit::decode(flags_); } - // Returns true if load from this slot can return sentinel value. - bool is_sentinel_visible() const { - return IsSentinelVisibleBit::decode(flags_); - } - - // Static type of the slots if any. - // - // A value that is read from the slot is guaranteed to be assignable to its - // static type. - const AbstractType& static_type() const; - - // More precise type information about values that can be read from this slot. - CompileType ComputeCompileType() const; + // Type information about values that can be read from this slot. + CompileType type() const { return type_; } const Field& field() const { ASSERT(IsDartField()); @@ -360,39 +346,32 @@ class Slot : public ZoneAllocated { private: Slot(Kind kind, int8_t flags, - ClassIdTagType cid, intptr_t offset_in_bytes, const void* data, - const AbstractType* static_type, + CompileType type, Representation representation, const FieldGuardState& field_guard_state = FieldGuardState()) : kind_(kind), flags_(flags), - cid_(cid), offset_in_bytes_(offset_in_bytes), representation_(representation), field_guard_state_(field_guard_state), data_(data), - static_type_(static_type) {} + type_(type) {} Slot(const Slot& other) : Slot(other.kind_, other.flags_, - other.cid_, other.offset_in_bytes_, other.data_, - other.static_type_, + other.type_, other.representation_, other.field_guard_state_) {} using IsImmutableBit = BitField; - using IsNullableBit = BitField; - using IsGuardedBit = BitField; + using IsGuardedBit = BitField; using IsCompressedBit = BitField; - using IsSentinelVisibleBit = - BitField; - using IsUnboxedBit = - BitField; + using IsUnboxedBit = BitField; template const T* DataAs() const { @@ -403,16 +382,12 @@ class Slot : public ZoneAllocated { Thread* thread, Kind kind, int8_t flags, - ClassIdTagType cid, intptr_t offset_in_bytes, const void* data, - const AbstractType* static_type, + CompileType type, Representation representation, const FieldGuardState& field_guard_state = FieldGuardState()); - // There is a fixed statically known number of native slots so we cache - // them statically. - static AcqRelAtomic native_fields_; static const Slot& GetNativeSlot(Kind kind); const FieldGuardState& field_guard_state() const { @@ -420,9 +395,7 @@ class Slot : public ZoneAllocated { } const Kind kind_; - const int8_t flags_; // is_immutable, is_nullable - const ClassIdTagType cid_; // Concrete cid of a value or kDynamicCid. - + const int8_t flags_; const intptr_t offset_in_bytes_; const Representation representation_; @@ -434,7 +407,7 @@ class Slot : public ZoneAllocated { // - Field object for Dart fields; const void* data_; - const AbstractType* static_type_; + CompileType type_; friend class SlotCache; }; diff --git a/runtime/vm/compiler/backend/slot_test.cc b/runtime/vm/compiler/backend/slot_test.cc index 9ba035f987f..f5f86ff72af 100644 --- a/runtime/vm/compiler/backend/slot_test.cc +++ b/runtime/vm/compiler/backend/slot_test.cc @@ -78,8 +78,8 @@ TEST_CASE(SlotFromGuardedField) { const Slot& slot2 = Slot::Get(field_clone_2, parsed_function); EXPECT_EQ(&slot1, &slot2); EXPECT(slot1.is_guarded_field()); - EXPECT(!slot1.is_nullable()); - EXPECT_EQ(kSmiCid, slot1.nullable_cid()); + EXPECT(!slot1.type().is_nullable()); + EXPECT_EQ(kSmiCid, slot1.type().ToCid()); // Check that the field was added (once) to the list of guarded fields. EXPECT_EQ(1, parsed_function->guarded_fields()->Length()); diff --git a/runtime/vm/compiler/backend/type_propagator.cc b/runtime/vm/compiler/backend/type_propagator.cc index 1b5d77b9662..1eeb969badc 100644 --- a/runtime/vm/compiler/backend/type_propagator.cc +++ b/runtime/vm/compiler/backend/type_propagator.cc @@ -690,6 +690,18 @@ CompileType CompileType::FromCid(intptr_t cid) { return CompileType(cid == kNullCid, cid == kSentinelCid, cid, nullptr); } +CompileType CompileType::FromUnboxedRepresentation(Representation rep) { + ASSERT(rep != kTagged); + ASSERT(rep != kUntagged); + if (RepresentationUtils::IsUnboxedInteger(rep)) { + if (!Boxing::RequiresAllocation(rep)) { + return CompileType::Smi(); + } + return CompileType::Int(); + } + return CompileType::FromCid(Boxing::BoxCid(rep)); +} + CompileType CompileType::Dynamic() { return CompileType(kCanBeNull, kCannotBeSentinel, kDynamicCid, &Object::dynamic_type()); @@ -1698,7 +1710,7 @@ CompileType LoadFieldInstr::ComputeType() const { } } } - CompileType type = slot().ComputeCompileType(); + CompileType type = slot().type(); if (calls_initializer()) { type = type.CopyNonSentinel(); } @@ -1974,8 +1986,8 @@ static CompileType ComputeArrayElementType(Value* array) { // type arguments which can be used to figure out element type. if (auto* load_field = array->definition()->AsLoadField()) { if (load_field->slot().IsDartField()) { - elem_type = - ExtractElementTypeFromArrayType(load_field->slot().static_type()); + elem_type = load_field->slot().field().type(); + elem_type = ExtractElementTypeFromArrayType(elem_type); } } return CompileType::FromAbstractType(elem_type, CompileType::kCanBeNull, diff --git a/runtime/vm/compiler/call_specializer.cc b/runtime/vm/compiler/call_specializer.cc index 200d36f26f0..09324b767ea 100644 --- a/runtime/vm/compiler/call_specializer.cc +++ b/runtime/vm/compiler/call_specializer.cc @@ -776,7 +776,7 @@ void CallSpecializer::InlineImplicitInstanceGetter(Definition* call, } ReplaceCall(call, load); - if (load->slot().nullable_cid() != kDynamicCid) { + if (load->slot().type().ToNullableCid() != kDynamicCid) { // Reset value types if we know concrete cid. for (Value::Iterator it(load->input_use_list()); !it.Done(); it.Advance()) { it.Current()->SetReachingType(nullptr); diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc index dce904cdd4c..d294ac17af3 100644 --- a/runtime/vm/stub_code.cc +++ b/runtime/vm/stub_code.cc @@ -97,6 +97,8 @@ CodePtr StubCode::Generate(const char* name, SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock()); compiler::Assembler assembler(object_pool_builder); + CompilerState compiler_state(thread, /*is_aot=*/FLAG_precompiled_mode, + /*is_optimizing=*/false); Zone* zone = thread->zone(); auto* pc_descriptors_list = new (zone) DescriptorList(zone); compiler::StubCodeCompiler stubCodeCompiler(&assembler, pc_descriptors_list); @@ -225,6 +227,8 @@ CodePtr StubCode::GetAllocationStubForClass(const Class& cls) { } compiler::Assembler assembler(wrapper); + CompilerState compiler_state(thread, /*is_aot=*/FLAG_precompiled_mode, + /*is_optimizing=*/false); compiler::UnresolvedPcRelativeCalls unresolved_calls; const char* name = cls.ToCString(); compiler::StubCodeCompiler stubCodeCompiler(&assembler, nullptr); @@ -323,6 +327,8 @@ CodePtr StubCode::GetBuildMethodExtractorStub(compiler::ObjectPoolBuilder* pool, compiler::ObjectPoolBuilder object_pool_builder; compiler::Assembler assembler(pool != nullptr ? pool : &object_pool_builder); + CompilerState compiler_state(thread, /*is_aot=*/FLAG_precompiled_mode, + /*is_optimizing=*/false); compiler::StubCodeCompiler stubCodeCompiler(&assembler, nullptr); stubCodeCompiler.GenerateBuildMethodExtractorStub( closure_allocation_stub, context_allocation_stub, generic); diff --git a/runtime/vm/type_testing_stubs.cc b/runtime/vm/type_testing_stubs.cc index d18309f21bc..f8051c8e38d 100644 --- a/runtime/vm/type_testing_stubs.cc +++ b/runtime/vm/type_testing_stubs.cc @@ -260,6 +260,9 @@ CodePtr TypeTestingStubGenerator::BuildCodeForType(const AbstractType& type) { slow_tts_stub = thread->isolate_group()->object_store()->slow_tts_stub(); } + CompilerState compiler_state(thread, /*is_aot=*/FLAG_precompiled_mode, + /*is_optimizing=*/false); + const Code& code = Code::Handle( thread->zone(), RetryCompilationWithFarBranches(