Index: runtime/vm/class_finalizer.cc |
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc |
index 98d74ff073efddae795a4921b18cbceedb87f616..3c5d45848ddd0b4414d591b23d37c04df43b9394 100644 |
--- a/runtime/vm/class_finalizer.cc |
+++ b/runtime/vm/class_finalizer.cc |
@@ -118,7 +118,7 @@ static void CollectImmediateSuperInterfaces(const Class& cls, |
// Processing ObjectStore::pending_classes_ occurs: |
// a) when bootstrap process completes (VerifyBootstrapClasses). |
// b) after the user classes are loaded (dart_api). |
-bool ClassFinalizer::ProcessPendingClasses() { |
+bool ClassFinalizer::ProcessPendingClasses(bool from_kernel) { |
Thread* thread = Thread::Current(); |
NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(), |
"ProcessPendingClasses")); |
@@ -150,6 +150,12 @@ bool ClassFinalizer::ProcessPendingClasses() { |
for (intptr_t i = 0; i < class_array.Length(); i++) { |
cls ^= class_array.At(i); |
FinalizeTypesInClass(cls); |
+ // Classes compiled from Dart sources are finalized more lazily, classes |
+ // compiled from Kernel binaries can be finalized now (and should be, |
+ // since we will not revisit them). |
+ if (from_kernel) { |
+ FinalizeClass(cls); |
+ } |
} |
if (FLAG_print_classes) { |
for (intptr_t i = 0; i < class_array.Length(); i++) { |
@@ -188,7 +194,7 @@ void ClassFinalizer::CollectInterfaces(const Class& cls, |
} |
-#if defined(DART_NO_SNAPSHOT) |
+#if !defined(DART_PRECOMPILED_RUNTIME) |
void ClassFinalizer::VerifyBootstrapClasses() { |
if (FLAG_trace_class_finalization) { |
OS::Print("VerifyBootstrapClasses START.\n"); |
@@ -254,7 +260,7 @@ void ClassFinalizer::VerifyBootstrapClasses() { |
} |
Isolate::Current()->heap()->Verify(); |
} |
-#endif // defined(DART_NO_SNAPSHOT). |
+#endif // !defined(DART_PRECOMPILED_RUNTIME) |
static bool IsLoaded(const Type& type) { |
@@ -263,9 +269,15 @@ static bool IsLoaded(const Type& type) { |
} |
const UnresolvedClass& unresolved_class = |
UnresolvedClass::Handle(type.unresolved_class()); |
- const LibraryPrefix& prefix = |
- LibraryPrefix::Handle(unresolved_class.library_prefix()); |
- return prefix.IsNull() || prefix.is_loaded(); |
+ const Object& prefix = |
+ Object::Handle(unresolved_class.library_or_library_prefix()); |
+ if (prefix.IsNull()) { |
+ return true; |
+ } else if (prefix.IsLibraryPrefix()) { |
+ return LibraryPrefix::Cast(prefix).is_loaded(); |
+ } else { |
+ return true; |
+ } |
} |
@@ -276,15 +288,19 @@ RawClass* ClassFinalizer::ResolveClass( |
const String& class_name = String::Handle(unresolved_class.ident()); |
Library& lib = Library::Handle(); |
Class& resolved_class = Class::Handle(); |
- if (unresolved_class.library_prefix() == LibraryPrefix::null()) { |
+ if (unresolved_class.library_or_library_prefix() == Object::null()) { |
lib = cls.library(); |
ASSERT(!lib.IsNull()); |
resolved_class = lib.LookupClass(class_name); |
} else { |
- LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); |
- lib_prefix = unresolved_class.library_prefix(); |
- ASSERT(!lib_prefix.IsNull()); |
- resolved_class = lib_prefix.LookupClass(class_name); |
+ const Object& prefix = |
+ Object::Handle(unresolved_class.library_or_library_prefix()); |
+ |
+ if (prefix.IsLibraryPrefix()) { |
+ resolved_class = LibraryPrefix::Cast(prefix).LookupClass(class_name); |
+ } else { |
+ resolved_class = Library::Cast(prefix).LookupClass(class_name); |
+ } |
} |
return resolved_class.raw(); |
} |
@@ -2189,12 +2205,25 @@ void ClassFinalizer::ApplyMixinMembers(const Class& cls) { |
const GrowableObjectArray& cloned_funcs = |
GrowableObjectArray::Handle(zone, GrowableObjectArray::New()); |
- CreateForwardingConstructors(cls, mixin_cls, cloned_funcs); |
- |
Array& functions = Array::Handle(zone); |
Function& func = Function::Handle(zone); |
+ |
// The parser creates the mixin application class with no functions. |
- ASSERT((functions = cls.functions(), functions.Length() == 0)); |
+ // But the Kernel frontend will generate mixin classes with only |
+ // constructors inside them, which forward to the base class constructors. |
+ // |
+ // => We generate the constructors if they are not already there. |
+ functions = cls.functions(); |
+ if (functions.Length() == 0) { |
+ CreateForwardingConstructors(cls, mixin_cls, cloned_funcs); |
+ } else { |
+ for (intptr_t i = 0; i < functions.Length(); i++) { |
+ func ^= functions.At(i); |
+ ASSERT(func.kernel_function() != 0); |
+ cloned_funcs.Add(func); |
+ } |
+ } |
+ |
// Now clone the functions from the mixin class. |
functions = mixin_cls.functions(); |
const intptr_t num_functions = functions.Length(); |
@@ -2384,8 +2413,20 @@ void ClassFinalizer::FinalizeTypesInClass(const Class& cls) { |
// if the class is being refinalized because a patch is being applied |
// after the class has been finalized then it is ok for the class to have |
// functions. |
- ASSERT((Array::Handle(cls.functions()).Length() == 0) || |
- cls.is_refinalize_after_patch()); |
+ // |
+ // TODO(kmillikin): This ASSERT will fail when bootstrapping from Kernel |
+ // because classes are first created, methods are added, and then classes |
+ // are finalized. It is not easy to finalize classes earlier because not |
+ // all bootstrap classes have been created yet. It would be possible to |
+ // create all classes, delay adding methods, finalize the classes, and then |
+ // reprocess all classes to add methods, but that seems unnecessary. |
+ // Marking the bootstrap classes as is_refinalize_after_patch seems cute but |
+ // it causes other things to fail by violating their assumptions. Reenable |
+ // this ASSERT if it's important, remove it if it's just a sanity check and |
+ // not required for correctness. |
+ // |
+ // ASSERT((Array::Handle(cls.functions()).Length() == 0) || |
+ // cls.is_refinalize_after_patch()); |
} |
} |