Chromium Code Reviews| Index: runtime/vm/class_finalizer.cc |
| diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc |
| index 8d9c266b2d3521dffed4b4316cce262c7bfbc329..f752a2819bef1e9c2599ab1384b544b4b6030d65 100644 |
| --- a/runtime/vm/class_finalizer.cc |
| +++ b/runtime/vm/class_finalizer.cc |
| @@ -117,7 +117,7 @@ static void CollectImmediateSuperInterfaces( |
| // 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")); |
| @@ -149,6 +149,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). |
|
hausner
2016/11/09 00:42:49
Why? Would be nice to have a brief explanation.
Vyacheslav Egorov (Google)
2016/11/09 14:43:16
The original idea behind Kernel was to be an AOT r
|
| + if (from_kernel) { |
| + FinalizeClass(cls); |
| + } |
| } |
| if (FLAG_print_classes) { |
| for (intptr_t i = 0; i < class_array.Length(); i++) { |
| @@ -187,7 +193,6 @@ void ClassFinalizer::CollectInterfaces( |
| } |
| -#if defined(DART_NO_SNAPSHOT) |
| void ClassFinalizer::VerifyBootstrapClasses() { |
| if (FLAG_trace_class_finalization) { |
| OS::Print("VerifyBootstrapClasses START.\n"); |
| @@ -253,7 +258,6 @@ void ClassFinalizer::VerifyBootstrapClasses() { |
| } |
| Isolate::Current()->heap()->Verify(); |
| } |
| -#endif // defined(DART_NO_SNAPSHOT). |
| static bool IsLoaded(const Type& type) { |
| @@ -262,9 +266,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; |
| + } |
| } |
| @@ -275,15 +285,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(); |
| } |
| @@ -2244,12 +2258,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(); |
| @@ -2444,8 +2471,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()); |
| } |
| } |