[vm] Replace cycle_free and type_finalized bits with class loading state
This change renames Class::is_cycle_free to Class::is_declaration_loaded
and under the hood replaces cycle_free and type_finalized bits with
class loading state enum.
Also, added new assertions to check is_declaration_loaded().
Change-Id: Ib43e12731d0dc782e273be8e55912494e102cd79
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/104920
Reviewed-by: RĂ©gis Crelier <regis@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 88858e7..18173a7 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -191,15 +191,15 @@
class_array = object_store->pending_classes();
ASSERT(!class_array.IsNull());
Class& cls = Class::Handle();
- // Mark all classes as cycle-free (should be checked by front-end).
- // TODO(alexmarkov): Cleanup is_cycle_free bit on classes.
+
+#if defined(DEBUG)
for (intptr_t i = 0; i < class_array.Length(); i++) {
cls ^= class_array.At(i);
- if (!cls.is_cycle_free()) {
- cls.set_is_cycle_free();
- }
+ ASSERT(cls.is_declaration_loaded());
}
- // Finalize all classes.
+#endif
+
+ // Finalize types in all classes.
for (intptr_t i = 0; i < class_array.Length(); i++) {
cls ^= class_array.At(i);
FinalizeTypesInClass(cls);
@@ -1005,6 +1005,7 @@
void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
Thread* thread = Thread::Current();
HANDLESCOPE(thread);
+ ASSERT(cls.is_declaration_loaded());
if (cls.is_type_finalized()) {
return;
}
diff --git a/runtime/vm/class_finalizer_test.cc b/runtime/vm/class_finalizer_test.cc
index a1440d2..7768c44 100644
--- a/runtime/vm/class_finalizer_test.cc
+++ b/runtime/vm/class_finalizer_test.cc
@@ -16,6 +16,7 @@
const Class& cls = Class::Handle(Class::New(
Library::Handle(), class_name, script, TokenPosition::kNoSource));
cls.set_interfaces(Object::empty_array());
+ cls.set_is_declaration_loaded();
cls.SetFunctions(Object::empty_array());
cls.SetFields(Object::empty_array());
return cls.raw();
diff --git a/runtime/vm/kernel_loader.cc b/runtime/vm/kernel_loader.cc
index 4186f23..c7e57fce 100644
--- a/runtime/vm/kernel_loader.cc
+++ b/runtime/vm/kernel_loader.cc
@@ -1066,8 +1066,8 @@
Class& toplevel_class =
Class::Handle(Z, Class::New(library, Symbols::TopLevel(), script,
TokenPosition::kNoSource, register_class));
+ toplevel_class.set_is_declaration_loaded();
toplevel_class.set_is_type_finalized();
- toplevel_class.set_is_cycle_free();
library.set_toplevel_class(toplevel_class);
library_helper.ReadUntilExcluding(LibraryHelper::kDependencies);
@@ -1386,6 +1386,8 @@
if (class_helper->is_transformed_mixin_application()) {
klass->set_is_transformed_mixin_application();
}
+
+ klass->set_is_declaration_loaded();
}
void KernelLoader::LoadClass(const Library& library,
@@ -1438,10 +1440,9 @@
helper_.ReadListLength(); // read type_parameters list length.
ActiveClassScope active_class_scope(&active_class_, out_class);
- if (!out_class->is_cycle_free()) {
+ if (!out_class->is_declaration_loaded()) {
LoadPreliminaryClass(&class_helper, type_parameter_counts);
} else {
- // do not use type parameters with cycle_free
ASSERT(type_parameter_counts == 0);
class_helper.SetJustRead(ClassHelper::kTypeParameters);
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 08b8a5f..40a56d7 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -533,8 +533,8 @@
cls.set_id(Class::kClassId);
cls.set_state_bits(0);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
cls.set_type_arguments_field_offset_in_words(Class::kNoTypeArguments);
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
@@ -555,16 +555,16 @@
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
// Allocate and initialize the forwarding corpse class.
cls = Class::New<ForwardingCorpse::FakeInstance>(kForwardingCorpse);
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
// Allocate and initialize the sentinel values of Null class.
{
@@ -832,22 +832,22 @@
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
dynamic_class_ = cls.raw();
cls = Class::New<Instance>(kVoidCid);
cls.set_num_type_arguments(0);
cls.set_num_own_type_arguments(0);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
void_class_ = cls.raw();
cls = Class::New<Type>();
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
- cls.set_is_cycle_free();
cls = dynamic_class_;
*dynamic_type_ = Type::NewNonParameterizedType(cls);
@@ -1604,7 +1604,6 @@
// Class that represents the Dart class _Closure and C++ class Closure.
cls = Class::New<Closure>();
object_store->set_closure_class(cls);
- cls.ResetFinalization(); // To calculate field offsets from Dart source.
RegisterPrivateClass(cls, Symbols::_Closure(), core_lib);
pending_classes.Add(cls);
@@ -2309,8 +2308,10 @@
(FakeObject::kClassId == kTypeArgumentsCid)) {
// VM internal classes are done. There is no finalization needed or
// possible in this case.
+ result.set_is_declaration_loaded();
+ result.set_is_type_finalized();
result.set_is_finalized();
- } else {
+ } else if (FakeObject::kClassId != kClosureCid) {
// VM backed classes are almost ready: run checks and resolve class
// references, but do not recompute size.
result.set_is_prefinalized();
@@ -3739,9 +3740,9 @@
cls.set_next_field_offset(instance_size);
cls.set_num_native_fields(field_count);
cls.set_is_finalized();
+ cls.set_is_declaration_loaded();
cls.set_is_type_finalized();
cls.set_is_synthesized_class();
- cls.set_is_cycle_free();
cls.set_kernel_offset(-1);
library.AddClass(cls);
return cls.raw();
@@ -4069,8 +4070,17 @@
set_state_bits(AbstractBit::update(true, raw_ptr()->state_bits_));
}
+void Class::set_is_declaration_loaded() const {
+ ASSERT(!is_declaration_loaded());
+ set_state_bits(ClassLoadingBits::update(RawClass::kDeclarationLoaded,
+ raw_ptr()->state_bits_));
+}
+
void Class::set_is_type_finalized() const {
- set_state_bits(TypeFinalizedBit::update(true, raw_ptr()->state_bits_));
+ ASSERT(is_declaration_loaded());
+ ASSERT(!is_type_finalized());
+ set_state_bits(ClassLoadingBits::update(RawClass::kTypeFinalized,
+ raw_ptr()->state_bits_));
}
void Class::set_is_patch() const {
@@ -4098,11 +4108,6 @@
set_state_bits(FieldsMarkedNullableBit::update(true, raw_ptr()->state_bits_));
}
-void Class::set_is_cycle_free() const {
- ASSERT(!is_cycle_free());
- set_state_bits(CycleFreeBit::update(true, raw_ptr()->state_bits_));
-}
-
void Class::set_is_allocated(bool value) const {
set_state_bits(IsAllocatedBit::update(value, raw_ptr()->state_bits_));
}
@@ -4117,13 +4122,6 @@
ClassFinalizedBits::update(RawClass::kFinalized, raw_ptr()->state_bits_));
}
-void Class::ResetFinalization() const {
- ASSERT(IsTopLevel() || IsClosureClass());
- set_state_bits(
- ClassFinalizedBits::update(RawClass::kAllocated, raw_ptr()->state_bits_));
- set_state_bits(TypeFinalizedBit::update(false, raw_ptr()->state_bits_));
-}
-
void Class::set_is_prefinalized() const {
ASSERT(!is_finalized());
set_state_bits(ClassFinalizedBits::update(RawClass::kPreFinalized,
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 453e847..99bd0f6 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -950,7 +950,10 @@
}
// The super type of this class, Object type if not explicitly specified.
- RawAbstractType* super_type() const { return raw_ptr()->super_type_; }
+ RawAbstractType* super_type() const {
+ ASSERT(is_declaration_loaded());
+ return raw_ptr()->super_type_;
+ }
void set_super_type(const AbstractType& value) const;
static intptr_t super_type_offset() {
return OFFSET_OF(RawClass, super_type_);
@@ -1117,8 +1120,17 @@
}
void set_is_abstract() const;
+ RawClass::ClassLoadingState class_loading_state() const {
+ return ClassLoadingBits::decode(raw_ptr()->state_bits_);
+ }
+
+ bool is_declaration_loaded() const {
+ return class_loading_state() >= RawClass::kDeclarationLoaded;
+ }
+ void set_is_declaration_loaded() const;
+
bool is_type_finalized() const {
- return TypeFinalizedBit::decode(raw_ptr()->state_bits_);
+ return class_loading_state() >= RawClass::kTypeFinalized;
}
void set_is_type_finalized() const;
@@ -1146,8 +1158,6 @@
void set_is_prefinalized() const;
- void ResetFinalization() const;
-
bool is_const() const { return ConstBit::decode(raw_ptr()->state_bits_); }
void set_is_const() const;
@@ -1167,11 +1177,6 @@
}
void set_is_fields_marked_nullable() const;
- bool is_cycle_free() const {
- return CycleFreeBit::decode(raw_ptr()->state_bits_);
- }
- void set_is_cycle_free() const;
-
bool is_allocated() const {
return IsAllocatedBit::decode(raw_ptr()->state_bits_);
}
@@ -1334,16 +1339,16 @@
enum StateBits {
kConstBit = 0,
kImplementedBit = 1,
- kTypeFinalizedBit = 2,
- kClassFinalizedPos = 3,
+ kClassFinalizedPos = 2,
kClassFinalizedSize = 2,
- kAbstractBit = kClassFinalizedPos + kClassFinalizedSize, // = 5
- kPatchBit = 6,
+ kClassLoadingPos = kClassFinalizedPos + kClassFinalizedSize, // = 4
+ kClassLoadingSize = 2,
+ kAbstractBit = kClassLoadingPos + kClassLoadingSize, // = 6
+ kPatchBit,
kSynthesizedClassBit,
kMixinAppAliasBit,
kMixinTypeAppliedBit,
kFieldsMarkedNullableBit,
- kCycleFreeBit,
kEnumBit,
kTransformedMixinApplicationBit,
kIsAllocatedBit,
@@ -1351,19 +1356,20 @@
};
class ConstBit : public BitField<uint16_t, bool, kConstBit, 1> {};
class ImplementedBit : public BitField<uint16_t, bool, kImplementedBit, 1> {};
- class TypeFinalizedBit
- : public BitField<uint16_t, bool, kTypeFinalizedBit, 1> {};
class ClassFinalizedBits : public BitField<uint16_t,
RawClass::ClassFinalizedState,
kClassFinalizedPos,
kClassFinalizedSize> {};
+ class ClassLoadingBits : public BitField<uint16_t,
+ RawClass::ClassLoadingState,
+ kClassLoadingPos,
+ kClassLoadingSize> {};
class AbstractBit : public BitField<uint16_t, bool, kAbstractBit, 1> {};
class PatchBit : public BitField<uint16_t, bool, kPatchBit, 1> {};
class SynthesizedClassBit
: public BitField<uint16_t, bool, kSynthesizedClassBit, 1> {};
class FieldsMarkedNullableBit
: public BitField<uint16_t, bool, kFieldsMarkedNullableBit, 1> {};
- class CycleFreeBit : public BitField<uint16_t, bool, kCycleFreeBit, 1> {};
class EnumBit : public BitField<uint16_t, bool, kEnumBit, 1> {};
class TransformedMixinApplicationBit
: public BitField<uint16_t, bool, kTransformedMixinApplicationBit, 1> {};
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index ace33b6..0921cc8 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -31,6 +31,7 @@
const Class& cls = Class::Handle(Class::New(
Library::Handle(), class_name, script, TokenPosition::kNoSource));
cls.set_is_synthesized_class(); // Dummy class for testing.
+ cls.set_is_declaration_loaded();
return cls.raw();
}
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index 355cb6b..629723c 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -735,6 +735,19 @@
kPreFinalized, // VM classes: size precomputed, but no checks done.
kFinalized, // Class parsed, finalized and ready for use.
};
+ enum ClassLoadingState {
+ // Class object is created, but it is not filled up.
+ // At this state class can only be used as a forward reference during
+ // class loading.
+ kNameOnly = 0,
+ // Class declaration information such as type parameters, supertype and
+ // implemented interfaces are loaded. However, types in the class are
+ // not finalized yet.
+ kDeclarationLoaded,
+ // Types in the class are finalized. At this point, members can be loaded
+ // and class can be finalized.
+ kTypeFinalized,
+ };
private:
RAW_HEAP_OBJECT_IMPLEMENTATION(Class);