| 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());
|
| }
|
| }
|
|
|
|
|