[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>
This commit is contained in:
Alexander Markov 2019-06-05 01:05:51 +00:00 committed by commit-bot@chromium.org
parent cf4a9f4f75
commit 9dcb026b26
7 changed files with 69 additions and 48 deletions

View file

@ -191,15 +191,15 @@ bool ClassFinalizer::ProcessPendingClasses() {
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 @@ static void MarkImplemented(Zone* zone, const Class& iface) {
void ClassFinalizer::FinalizeTypesInClass(const Class& cls) {
Thread* thread = Thread::Current();
HANDLESCOPE(thread);
ASSERT(cls.is_declaration_loaded());
if (cls.is_type_finalized()) {
return;
}

View file

@ -16,6 +16,7 @@ static RawClass* CreateTestClass(const char* name) {
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();

View file

@ -1066,8 +1066,8 @@ RawLibrary* KernelLoader::LoadLibrary(intptr_t index) {
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 @@ void KernelLoader::LoadPreliminaryClass(ClassHelper* class_helper,
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 @@ void KernelLoader::LoadClass(const Library& library,
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);
}

View file

@ -533,8 +533,8 @@ void Object::Init(Isolate* isolate) {
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 @@ void Object::Init(Isolate* isolate) {
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 @@ void Object::Init(Isolate* isolate) {
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 @@ RawError* Object::Init(Isolate* isolate,
// 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 @@ RawClass* Class::New() {
(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 @@ RawClass* Class::NewNativeWrapper(const Library& library,
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 @@ void Class::set_is_abstract() const {
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 @@ void Class::set_is_fields_marked_nullable() const {
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 @@ void Class::set_is_finalized() const {
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,

View file

@ -950,7 +950,10 @@ class Class : public Object {
}
// 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 @@ class Class : public Object {
}
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 @@ class Class : public Object {
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 @@ class Class : public Object {
}
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 @@ class Class : public Object {
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 Class : public Object {
};
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> {};

View file

@ -31,6 +31,7 @@ static RawClass* CreateDummyClass(const String& class_name,
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();
}

View file

@ -735,6 +735,19 @@ class RawClass : public RawObject {
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);