Chromium Code Reviews| Index: runtime/vm/class_finalizer.cc |
| =================================================================== |
| --- runtime/vm/class_finalizer.cc (revision 1336) |
| +++ runtime/vm/class_finalizer.cc (working copy) |
| @@ -18,8 +18,22 @@ |
| "Verify that all classes implement their interface."); |
| DECLARE_FLAG(bool, enable_type_checks); |
| +void ClassFinalizer::ExpectPendingClasses() { |
|
srdjan
2011/11/09 21:22:43
Do you want to allow ExpectPendingClasses several
regis
2011/11/09 23:31:01
Good question!
Currently, there may be several cal
|
| + if (AllClassesFinalized()) { |
| + ObjectStore* object_store = Isolate::Current()->object_store(); |
| + object_store->set_pending_classes(Array::Handle(Array::Empty())); |
| + ASSERT(!AllClassesFinalized()); |
| + } |
| +} |
| + |
| + |
| void ClassFinalizer::AddPendingClasses( |
| const GrowableArray<const Class*>& classes) { |
| + // ExpectPendingClasses() must be called prior to calling AddPendingClasses(). |
| + if (AllClassesFinalized()) { // TODO(regis): DEBUG. |
| + ASSERT(false); |
| + } |
|
srdjan
2011/11/09 21:22:43
Why the code above?
regis
2011/11/09 23:31:01
Left over debugging code. Removed.
|
| + ASSERT(!AllClassesFinalized()); |
| if (!classes.is_empty()) { |
| ObjectStore* object_store = Isolate::Current()->object_store(); |
| const Array& old_array = Array::Handle(object_store->pending_classes()); |
| @@ -38,7 +52,7 @@ |
| bool ClassFinalizer::AllClassesFinalized() { |
| ObjectStore* object_store = Isolate::Current()->object_store(); |
| const Array& classes = Array::Handle(object_store->pending_classes()); |
| - return classes.Length() == 0; |
| + return classes.IsNull(); |
| } |
| @@ -59,10 +73,11 @@ |
| isolate->set_long_jump_base(&jump); |
| if (setjmp(*jump.Set()) == 0) { |
| const Array& class_array = Array::Handle(object_store->pending_classes()); |
| - ASSERT(!class_array.IsNull()); |
| + const intptr_t num_pending_classes = |
| + class_array.IsNull() ? 0 : class_array.Length(); |
| Class& cls = Class::Handle(); |
| // First resolve all superclasses. |
| - for (intptr_t i = 0; i < class_array.Length(); i++) { |
| + for (intptr_t i = 0; i < num_pending_classes; i++) { |
| cls ^= class_array.At(i); |
| if (FLAG_trace_class_finalization) { |
| OS::Print("Resolving super and default: %s\n", cls.ToCString()); |
| @@ -73,18 +88,18 @@ |
| } |
| } |
| // Finalize all classes. |
| - for (intptr_t i = 0; i < class_array.Length(); i++) { |
| + for (intptr_t i = 0; i < num_pending_classes; i++) { |
| cls ^= class_array.At(i); |
| FinalizeClass(cls); |
| } |
| if (FLAG_print_classes) { |
| - for (intptr_t i = 0; i < class_array.Length(); i++) { |
| + for (intptr_t i = 0; i < num_pending_classes; i++) { |
| cls ^= class_array.At(i); |
| PrintClassInformation(cls); |
| } |
| } |
| if (FLAG_verify_implements) { |
| - for (intptr_t i = 0; i < class_array.Length(); i++) { |
| + for (intptr_t i = 0; i < num_pending_classes; i++) { |
| cls ^= class_array.At(i); |
| if (!cls.is_interface()) { |
| VerifyClassImplements(cls); |
| @@ -92,7 +107,8 @@ |
| } |
| } |
| // Clear pending classes array. |
| - object_store->set_pending_classes(Array::Handle(Array::Empty())); |
| + object_store->set_pending_classes(Array::Handle()); |
| + ASSERT(AllClassesFinalized()); |
| // Check to ensure there are no duplicate definitions in the library |
| // hierarchy. |
| @@ -242,6 +258,38 @@ |
| } |
| +// Resolve unresolved_class in the library of cls. |
| +RawClass* ClassFinalizer::ResolveClass( |
| + const Class& cls, const UnresolvedClass& unresolved_class) { |
| + Library& lib = Library::Handle(); |
| + if (unresolved_class.qualifier() == String::null()) { |
| + lib = cls.library(); |
| + } else { |
| + const String& qualifier = String::Handle(unresolved_class.qualifier()); |
| + LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
| + lib_prefix = cls.LookupLibraryPrefix(qualifier); |
| + if (lib_prefix.IsNull()) { |
| + const Script& script = Script::Handle(cls.script()); |
| + ReportError(script, unresolved_class.token_index(), |
| + "cannot resolve name '%s'\n", |
|
srdjan
2011/11/09 21:22:43
Maybe be more specific -> cannot resolve library p
regis
2011/11/09 23:31:01
Done.
|
| + String::Handle(unresolved_class.Name()).ToCString()); |
| + } |
| + lib = lib_prefix.library(); |
| + } |
| + ASSERT(!lib.IsNull()); |
| + const String& class_name = String::Handle(unresolved_class.ident()); |
| + const Class& resolved_class = Class::Handle(lib.LookupClass(class_name)); |
| + if (resolved_class.IsNull()) { |
| + const Script& script = Script::Handle(cls.script()); |
| + ReportError(script, unresolved_class.token_index(), |
| + "cannot resolve class name '%s' from '%s'\n", |
| + String::Handle(unresolved_class.Name()).ToCString(), |
| + String::Handle(cls.Name()).ToCString()); |
| + } |
| + return resolved_class.raw(); |
| +} |
| + |
| + |
| // Resolve unresolved superclasses (String -> Class). |
| void ClassFinalizer::ResolveSuperClass(const Class& cls) { |
| if (cls.is_finalized()) { |
| @@ -253,6 +301,13 @@ |
| } |
| // Resolve failures lead to a longjmp. |
| super_type = ResolveType(cls, super_type); |
| + if (super_type.IsTypeParameter()) { |
| + String& class_name = String::Handle(cls.Name()); |
| + String& type_parameter_name = String::Handle(super_type.Name()); |
| + ReportError("'%s' cannot extend or implement type parameter '%s'.\n", |
| + class_name.ToCString(), |
| + type_parameter_name.ToCString()); |
| + } |
| cls.set_super_type(super_type); |
| const Class& super_class = Class::Handle(super_type.type_class()); |
| if (cls.is_interface() != super_class.is_interface()) { |
| @@ -354,31 +409,9 @@ |
| } |
| // Lookup the type class. |
| - Class& type_class = Class::Handle(); |
| - Library& lib = Library::Handle(); |
| - if (unresolved_class.qualifier() == String::null()) { |
| - lib = cls.library(); |
| - } else { |
| - const String& qualifier = String::Handle(unresolved_class.qualifier()); |
| - LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
| - lib_prefix = cls.LookupLibraryPrefix(qualifier); |
| - if (lib_prefix.IsNull()) { |
| - const Script& script = Script::Handle(cls.script()); |
| - ReportError(script, unresolved_class.token_index(), |
| - "cannot resolve name '%s'\n", |
| - String::Handle(unresolved_class.Name()).ToCString()); |
| - } |
| - lib = lib_prefix.library(); |
| - } |
| - ASSERT(!lib.IsNull()); |
| - type_class = lib.LookupClass(type_class_name); |
| - if (type_class.IsNull()) { |
| - const Script& script = Script::Handle(cls.script()); |
| - ReportError(script, unresolved_class.token_index(), |
| - "cannot resolve class name '%s' from '%s'\n", |
| - String::Handle(unresolved_class.Name()).ToCString(), |
| - String::Handle(cls.Name()).ToCString()); |
| - } |
| + const Class& type_class = |
| + Class::Handle(ResolveClass(cls, unresolved_class)); |
| + |
| // Replace unresolved class with resolved type class. |
| ASSERT(type.IsParameterizedType()); |
| ParameterizedType& parameterized_type = ParameterizedType::Handle(); |
| @@ -506,10 +539,18 @@ |
| } |
| // The type class does not need to be finalized in order to finalize the type, |
| - // however, it must at least be resolved. This was done as part of resolving |
| - // the type itself. |
| + // however, it must at least be resolved (this was done as part of resolving |
| + // the type itself, a precondition to calling FinalizeType) and the upper |
| + // bounds of its type parameters must be finalized (done here). |
| Class& type_class = Class::Handle(parameterized_type.type_class()); |
| + // If the type class is a signature class, finalize it, thereby finalizing the |
| + // result and parameter types of its signature function. |
| + // Do this before marking this type as finalized in order to detect cycles. |
| + if (type_class.IsSignatureClass()) { |
| + FinalizeClass(type_class); |
| + } |
| + |
| // The finalized type argument vector needs num_type_arguments types. |
| const intptr_t num_type_arguments = type_class.NumTypeArguments(); |
| // The type class has num_type_parameters type parameters. |
| @@ -545,14 +586,11 @@ |
| FinalizeTypeArguments(type_class, full_arguments); |
| parameterized_type.set_arguments(full_arguments); |
| } |
| + // Mark the type as finalized before finalizing the upper bounds, because |
| + // cycles via upper bounds are legal at compile time. |
| + parameterized_type.set_is_finalized(); |
| + ResolveAndFinalizeUpperBounds(type_class); |
| - // If the type is a function type, finalize the result and parameter types. |
| - if (type_class.IsSignatureClass()) { |
| - ResolveAndFinalizeSignature( |
| - type_class, Function::Handle(type_class.signature_function())); |
| - } |
| - |
| - parameterized_type.set_is_finalized(); |
| return parameterized_type.Canonicalize(); |
| } |
| @@ -565,7 +603,15 @@ |
| LongJump jump; |
| isolate->set_long_jump_base(&jump); |
| if (setjmp(*jump.Set()) == 0) { |
| - const Type& canonical_type = Type::Handle(FinalizeType(type)); |
| + Type& canonical_type = Type::Handle(); |
| + if (type.IsSignatureType() && !AllClassesFinalized()) { |
|
srdjan
2011/11/09 21:22:43
Maybe have a interim method: CollectingClassesToFi
regis
2011/11/09 23:31:01
Done. Renamed these calls to:
ExpectClassesToFinal
|
| + // Postpone the finalization of this signature type and class. |
| + GrowableArray<const Class*> classes; |
| + classes.Add(&Class::ZoneHandle(type.type_class())); |
| + ClassFinalizer::AddPendingClasses(classes); |
| + } else { |
| + canonical_type = FinalizeType(type); |
| + } |
| isolate->set_long_jump_base(base); |
| *errmsg = String::null(); |
| return canonical_type.raw(); |
| @@ -580,11 +626,6 @@ |
| } |
| -// Top level function signatures are canonicalized, added to the library class |
| -// dictionary, and finalized with other library classes and interfaces. |
| -// Function signatures used as type of a local variable or of a local function |
| -// are canonicalized and finalized upon creation, since all the types they |
| -// reference are already resolved. |
| void ClassFinalizer::ResolveAndFinalizeSignature(const Class& cls, |
| const Function& function) { |
| // Resolve result type. |
| @@ -644,6 +685,23 @@ |
| } |
| +void ClassFinalizer::ResolveAndFinalizeUpperBounds(const Class& cls) { |
| + const intptr_t num_type_params = cls.NumTypeParameters(); |
| + Type& type_extends = Type::Handle(); |
| + const TypeArguments& extends_array = |
| + TypeArguments::Handle(cls.type_parameter_extends()); |
| + ASSERT((extends_array.IsNull() && (num_type_params == 0)) || |
| + (extends_array.Length() == num_type_params)); |
| + for (intptr_t i = 0; i < num_type_params; i++) { |
| + type_extends = extends_array.TypeAt(i); |
| + type_extends = ResolveType(cls, type_extends); |
| + extends_array.SetTypeAt(i, type_extends); |
| + type_extends = FinalizeType(type_extends); |
| + extends_array.SetTypeAt(i, type_extends); |
| + } |
| +} |
| + |
| + |
| void ClassFinalizer::ResolveAndFinalizeMemberTypes(const Class& cls) { |
| // Note that getters and setters are explicitly listed as such in the list of |
| // functions of a class, so we do not need to consider fields as implicitly |
| @@ -777,13 +835,6 @@ |
| } |
| } |
| } |
| - // Resolve the signature type if this class is a signature class. |
| - if (cls.IsSignatureClass()) { |
| - Type& signature_type = Type::Handle(cls.SignatureType()); |
| - signature_type = FinalizeType(signature_type); |
| - // Signature types are canonicalized by default. |
| - ASSERT(signature_type.raw() == cls.SignatureType()); |
| - } |
| } |
| @@ -833,9 +884,25 @@ |
| interface_type = FinalizeType(interface_type); |
| interface_types.SetAt(i, interface_type); |
| } |
| - // Mark as finalized before resolving member types in order to break cycles. |
| + // Mark as finalized before resolving type parameter upper bounds and member |
| + // types in order to break cycles. |
| cls.Finalize(); |
| + ResolveAndFinalizeUpperBounds(cls); |
| ResolveAndFinalizeMemberTypes(cls); |
| + |
| + if (cls.IsSignatureClass()) { |
| + // Finalize the signature type of this signature class. |
| + Type& signature_type = Type::Handle(cls.SignatureType()); |
| + signature_type = FinalizeType(signature_type); |
| + // Signature types are canonicalized by default. |
| + ASSERT(signature_type.raw() == cls.SignatureType()); |
| + |
| + // Resolve and finalize the result and parameter types of the signature |
| + // function of this signature class. |
| + ResolveAndFinalizeSignature(cls, |
| + Function::Handle(cls.signature_function())); |
| + } |
| + |
| // Run additional checks after all types are finalized. |
| if (cls.is_const()) { |
| CheckForLegalConstClass(cls); |
| @@ -964,8 +1031,6 @@ |
| String::Handle(cls.Name()).ToCString(), |
| String::Handle(interface_class.Name()).ToCString()); |
| } |
| - // TODO(regis): We also need to prevent extending classes Smi, Mint, |
| - // BigInt, Double, OneByteString, TwoByteString, FourByteString. |
| } |
| // Now resolve the super interfaces. |
| ResolveInterfaces(interface_class, visited); |