Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/class_finalizer.h" | 5 #include "vm/class_finalizer.h" |
| 6 | 6 |
| 7 #include "vm/code_generator.h" | 7 #include "vm/code_generator.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/heap.h" | 9 #include "vm/heap.h" |
| 10 #include "vm/isolate.h" | 10 #include "vm/isolate.h" |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 110 } | 110 } |
| 111 } | 111 } |
| 112 cids->Add(ifc.id()); | 112 cids->Add(ifc.id()); |
| 113 } | 113 } |
| 114 } | 114 } |
| 115 | 115 |
| 116 | 116 |
| 117 // Processing ObjectStore::pending_classes_ occurs: | 117 // Processing ObjectStore::pending_classes_ occurs: |
| 118 // a) when bootstrap process completes (VerifyBootstrapClasses). | 118 // a) when bootstrap process completes (VerifyBootstrapClasses). |
| 119 // b) after the user classes are loaded (dart_api). | 119 // b) after the user classes are loaded (dart_api). |
| 120 bool ClassFinalizer::ProcessPendingClasses() { | 120 bool ClassFinalizer::ProcessPendingClasses(bool from_kernel) { |
| 121 Thread* thread = Thread::Current(); | 121 Thread* thread = Thread::Current(); |
| 122 NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(), | 122 NOT_IN_PRODUCT(TimelineDurationScope tds(thread, Timeline::GetIsolateStream(), |
| 123 "ProcessPendingClasses")); | 123 "ProcessPendingClasses")); |
| 124 Isolate* isolate = thread->isolate(); | 124 Isolate* isolate = thread->isolate(); |
| 125 ASSERT(isolate != NULL); | 125 ASSERT(isolate != NULL); |
| 126 HANDLESCOPE(thread); | 126 HANDLESCOPE(thread); |
| 127 ObjectStore* object_store = isolate->object_store(); | 127 ObjectStore* object_store = isolate->object_store(); |
| 128 const Error& error = Error::Handle(thread->zone(), thread->sticky_error()); | 128 const Error& error = Error::Handle(thread->zone(), thread->sticky_error()); |
| 129 if (!error.IsNull()) { | 129 if (!error.IsNull()) { |
| 130 return false; | 130 return false; |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 142 // First resolve all superclasses. | 142 // First resolve all superclasses. |
| 143 for (intptr_t i = 0; i < class_array.Length(); i++) { | 143 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 144 cls ^= class_array.At(i); | 144 cls ^= class_array.At(i); |
| 145 GrowableArray<intptr_t> visited_interfaces; | 145 GrowableArray<intptr_t> visited_interfaces; |
| 146 ResolveSuperTypeAndInterfaces(cls, &visited_interfaces); | 146 ResolveSuperTypeAndInterfaces(cls, &visited_interfaces); |
| 147 } | 147 } |
| 148 // Finalize all classes. | 148 // Finalize all classes. |
| 149 for (intptr_t i = 0; i < class_array.Length(); i++) { | 149 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 150 cls ^= class_array.At(i); | 150 cls ^= class_array.At(i); |
| 151 FinalizeTypesInClass(cls); | 151 FinalizeTypesInClass(cls); |
| 152 // Classes compiled from Dart sources are finalized more lazily, classes | |
| 153 // compiled from Kernel binaries can be finalized now (and should be, | |
| 154 // 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
| |
| 155 if (from_kernel) { | |
| 156 FinalizeClass(cls); | |
| 157 } | |
| 152 } | 158 } |
| 153 if (FLAG_print_classes) { | 159 if (FLAG_print_classes) { |
| 154 for (intptr_t i = 0; i < class_array.Length(); i++) { | 160 for (intptr_t i = 0; i < class_array.Length(); i++) { |
| 155 cls ^= class_array.At(i); | 161 cls ^= class_array.At(i); |
| 156 PrintClassInformation(cls); | 162 PrintClassInformation(cls); |
| 157 } | 163 } |
| 158 } | 164 } |
| 159 // Clear pending classes array. | 165 // Clear pending classes array. |
| 160 class_array = GrowableObjectArray::New(); | 166 class_array = GrowableObjectArray::New(); |
| 161 object_store->set_pending_classes(class_array); | 167 object_store->set_pending_classes(class_array); |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 180 Class& interface_class = Class::Handle(zone); | 186 Class& interface_class = Class::Handle(zone); |
| 181 for (intptr_t i = 0; i < interface_array.Length(); i++) { | 187 for (intptr_t i = 0; i < interface_array.Length(); i++) { |
| 182 interface ^= interface_array.At(i); | 188 interface ^= interface_array.At(i); |
| 183 interface_class = interface.type_class(); | 189 interface_class = interface.type_class(); |
| 184 collected->Add(&Class::ZoneHandle(zone, interface_class.raw())); | 190 collected->Add(&Class::ZoneHandle(zone, interface_class.raw())); |
| 185 CollectInterfaces(interface_class, collected); | 191 CollectInterfaces(interface_class, collected); |
| 186 } | 192 } |
| 187 } | 193 } |
| 188 | 194 |
| 189 | 195 |
| 190 #if defined(DART_NO_SNAPSHOT) | |
| 191 void ClassFinalizer::VerifyBootstrapClasses() { | 196 void ClassFinalizer::VerifyBootstrapClasses() { |
| 192 if (FLAG_trace_class_finalization) { | 197 if (FLAG_trace_class_finalization) { |
| 193 OS::Print("VerifyBootstrapClasses START.\n"); | 198 OS::Print("VerifyBootstrapClasses START.\n"); |
| 194 } | 199 } |
| 195 ObjectStore* object_store = Isolate::Current()->object_store(); | 200 ObjectStore* object_store = Isolate::Current()->object_store(); |
| 196 | 201 |
| 197 Class& cls = Class::Handle(); | 202 Class& cls = Class::Handle(); |
| 198 #if defined(DEBUG) | 203 #if defined(DEBUG) |
| 199 // Basic checking. | 204 // Basic checking. |
| 200 cls = object_store->object_class(); | 205 cls = object_store->object_class(); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 246 const Error& err = Error::Handle(Thread::Current()->sticky_error()); | 251 const Error& err = Error::Handle(Thread::Current()->sticky_error()); |
| 247 OS::PrintErr("Could not verify bootstrap classes : %s\n", | 252 OS::PrintErr("Could not verify bootstrap classes : %s\n", |
| 248 err.ToErrorCString()); | 253 err.ToErrorCString()); |
| 249 OS::Exit(255); | 254 OS::Exit(255); |
| 250 } | 255 } |
| 251 if (FLAG_trace_class_finalization) { | 256 if (FLAG_trace_class_finalization) { |
| 252 OS::Print("VerifyBootstrapClasses END.\n"); | 257 OS::Print("VerifyBootstrapClasses END.\n"); |
| 253 } | 258 } |
| 254 Isolate::Current()->heap()->Verify(); | 259 Isolate::Current()->heap()->Verify(); |
| 255 } | 260 } |
| 256 #endif // defined(DART_NO_SNAPSHOT). | |
| 257 | 261 |
| 258 | 262 |
| 259 static bool IsLoaded(const Type& type) { | 263 static bool IsLoaded(const Type& type) { |
| 260 if (type.HasResolvedTypeClass()) { | 264 if (type.HasResolvedTypeClass()) { |
| 261 return true; | 265 return true; |
| 262 } | 266 } |
| 263 const UnresolvedClass& unresolved_class = | 267 const UnresolvedClass& unresolved_class = |
| 264 UnresolvedClass::Handle(type.unresolved_class()); | 268 UnresolvedClass::Handle(type.unresolved_class()); |
| 265 const LibraryPrefix& prefix = | 269 const Object& prefix = |
| 266 LibraryPrefix::Handle(unresolved_class.library_prefix()); | 270 Object::Handle(unresolved_class.library_or_library_prefix()); |
| 267 return prefix.IsNull() || prefix.is_loaded(); | 271 if (prefix.IsNull()) { |
| 272 return true; | |
| 273 } else if (prefix.IsLibraryPrefix()) { | |
| 274 return LibraryPrefix::Cast(prefix).is_loaded(); | |
| 275 } else { | |
| 276 return true; | |
| 277 } | |
| 268 } | 278 } |
| 269 | 279 |
| 270 | 280 |
| 271 // Resolve unresolved_class in the library of cls, or return null. | 281 // Resolve unresolved_class in the library of cls, or return null. |
| 272 RawClass* ClassFinalizer::ResolveClass( | 282 RawClass* ClassFinalizer::ResolveClass( |
| 273 const Class& cls, | 283 const Class& cls, |
| 274 const UnresolvedClass& unresolved_class) { | 284 const UnresolvedClass& unresolved_class) { |
| 275 const String& class_name = String::Handle(unresolved_class.ident()); | 285 const String& class_name = String::Handle(unresolved_class.ident()); |
| 276 Library& lib = Library::Handle(); | 286 Library& lib = Library::Handle(); |
| 277 Class& resolved_class = Class::Handle(); | 287 Class& resolved_class = Class::Handle(); |
| 278 if (unresolved_class.library_prefix() == LibraryPrefix::null()) { | 288 if (unresolved_class.library_or_library_prefix() == Object::null()) { |
| 279 lib = cls.library(); | 289 lib = cls.library(); |
| 280 ASSERT(!lib.IsNull()); | 290 ASSERT(!lib.IsNull()); |
| 281 resolved_class = lib.LookupClass(class_name); | 291 resolved_class = lib.LookupClass(class_name); |
| 282 } else { | 292 } else { |
| 283 LibraryPrefix& lib_prefix = LibraryPrefix::Handle(); | 293 const Object& prefix = |
| 284 lib_prefix = unresolved_class.library_prefix(); | 294 Object::Handle(unresolved_class.library_or_library_prefix()); |
| 285 ASSERT(!lib_prefix.IsNull()); | 295 |
| 286 resolved_class = lib_prefix.LookupClass(class_name); | 296 if (prefix.IsLibraryPrefix()) { |
| 297 resolved_class = LibraryPrefix::Cast(prefix).LookupClass(class_name); | |
| 298 } else { | |
| 299 resolved_class = Library::Cast(prefix).LookupClass(class_name); | |
| 300 } | |
| 287 } | 301 } |
| 288 return resolved_class.raw(); | 302 return resolved_class.raw(); |
| 289 } | 303 } |
| 290 | 304 |
| 291 | 305 |
| 292 | 306 |
| 293 void ClassFinalizer::ResolveRedirectingFactory(const Class& cls, | 307 void ClassFinalizer::ResolveRedirectingFactory(const Class& cls, |
| 294 const Function& factory) { | 308 const Function& factory) { |
| 295 const Function& target = Function::Handle(factory.RedirectionTarget()); | 309 const Function& target = Function::Handle(factory.RedirectionTarget()); |
| 296 if (target.IsNull()) { | 310 if (target.IsNull()) { |
| (...skipping 1940 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2237 if (FLAG_trace_class_finalization) { | 2251 if (FLAG_trace_class_finalization) { |
| 2238 THR_Print("Applying mixin members of %s to %s at pos %s\n", | 2252 THR_Print("Applying mixin members of %s to %s at pos %s\n", |
| 2239 mixin_cls.ToCString(), | 2253 mixin_cls.ToCString(), |
| 2240 cls.ToCString(), | 2254 cls.ToCString(), |
| 2241 cls.token_pos().ToCString()); | 2255 cls.token_pos().ToCString()); |
| 2242 } | 2256 } |
| 2243 | 2257 |
| 2244 const GrowableObjectArray& cloned_funcs = | 2258 const GrowableObjectArray& cloned_funcs = |
| 2245 GrowableObjectArray::Handle(zone, GrowableObjectArray::New()); | 2259 GrowableObjectArray::Handle(zone, GrowableObjectArray::New()); |
| 2246 | 2260 |
| 2247 CreateForwardingConstructors(cls, mixin_cls, cloned_funcs); | |
| 2248 | |
| 2249 Array& functions = Array::Handle(zone); | 2261 Array& functions = Array::Handle(zone); |
| 2250 Function& func = Function::Handle(zone); | 2262 Function& func = Function::Handle(zone); |
| 2263 | |
| 2251 // The parser creates the mixin application class with no functions. | 2264 // The parser creates the mixin application class with no functions. |
| 2252 ASSERT((functions = cls.functions(), functions.Length() == 0)); | 2265 // But the Kernel frontend will generate mixin classes with only |
| 2266 // constructors inside them, which forward to the base class constructors. | |
| 2267 // | |
| 2268 // => We generate the constructors if they are not already there. | |
| 2269 functions = cls.functions(); | |
| 2270 if (functions.Length() == 0) { | |
| 2271 CreateForwardingConstructors(cls, mixin_cls, cloned_funcs); | |
| 2272 } else { | |
| 2273 for (intptr_t i = 0; i < functions.Length(); i++) { | |
| 2274 func ^= functions.At(i); | |
| 2275 ASSERT(func.kernel_function() != 0); | |
| 2276 cloned_funcs.Add(func); | |
| 2277 } | |
| 2278 } | |
| 2279 | |
| 2253 // Now clone the functions from the mixin class. | 2280 // Now clone the functions from the mixin class. |
| 2254 functions = mixin_cls.functions(); | 2281 functions = mixin_cls.functions(); |
| 2255 const intptr_t num_functions = functions.Length(); | 2282 const intptr_t num_functions = functions.Length(); |
| 2256 for (intptr_t i = 0; i < num_functions; i++) { | 2283 for (intptr_t i = 0; i < num_functions; i++) { |
| 2257 func ^= functions.At(i); | 2284 func ^= functions.At(i); |
| 2258 if (func.IsGenerativeConstructor()) { | 2285 if (func.IsGenerativeConstructor()) { |
| 2259 // A mixin class must not have explicit constructors. | 2286 // A mixin class must not have explicit constructors. |
| 2260 if (!func.IsImplicitConstructor()) { | 2287 if (!func.IsImplicitConstructor()) { |
| 2261 const Script& script = Script::Handle(cls.script()); | 2288 const Script& script = Script::Handle(cls.script()); |
| 2262 const Error& error = Error::Handle( | 2289 const Error& error = Error::Handle( |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2437 } else { | 2464 } else { |
| 2438 // This class should not contain any functions or user-defined fields yet, | 2465 // This class should not contain any functions or user-defined fields yet, |
| 2439 // because it has not been compiled yet. There may however be metadata | 2466 // because it has not been compiled yet. There may however be metadata |
| 2440 // fields because type parameters are parsed before the class body. Since | 2467 // fields because type parameters are parsed before the class body. Since |
| 2441 // 'ResolveAndFinalizeMemberTypes(cls)' has not been called yet, unfinalized | 2468 // 'ResolveAndFinalizeMemberTypes(cls)' has not been called yet, unfinalized |
| 2442 // member types could choke the snapshotter. | 2469 // member types could choke the snapshotter. |
| 2443 // Or | 2470 // Or |
| 2444 // if the class is being refinalized because a patch is being applied | 2471 // if the class is being refinalized because a patch is being applied |
| 2445 // after the class has been finalized then it is ok for the class to have | 2472 // after the class has been finalized then it is ok for the class to have |
| 2446 // functions. | 2473 // functions. |
| 2447 ASSERT((Array::Handle(cls.functions()).Length() == 0) || | 2474 // |
| 2448 cls.is_refinalize_after_patch()); | 2475 // TODO(kmillikin): This ASSERT will fail when bootstrapping from Kernel |
| 2476 // because classes are first created, methods are added, and then classes | |
| 2477 // are finalized. It is not easy to finalize classes earlier because not | |
| 2478 // all bootstrap classes have been created yet. It would be possible to | |
| 2479 // create all classes, delay adding methods, finalize the classes, and then | |
| 2480 // reprocess all classes to add methods, but that seems unnecessary. | |
| 2481 // Marking the bootstrap classes as is_refinalize_after_patch seems cute but | |
| 2482 // it causes other things to fail by violating their assumptions. Reenable | |
| 2483 // this ASSERT if it's important, remove it if it's just a sanity check and | |
| 2484 // not required for correctness. | |
| 2485 // | |
| 2486 // ASSERT((Array::Handle(cls.functions()).Length() == 0) || | |
| 2487 // cls.is_refinalize_after_patch()); | |
| 2449 } | 2488 } |
| 2450 } | 2489 } |
| 2451 | 2490 |
| 2452 | 2491 |
| 2453 void ClassFinalizer::FinalizeClass(const Class& cls) { | 2492 void ClassFinalizer::FinalizeClass(const Class& cls) { |
| 2454 Thread* thread = Thread::Current(); | 2493 Thread* thread = Thread::Current(); |
| 2455 HANDLESCOPE(thread); | 2494 HANDLESCOPE(thread); |
| 2456 ASSERT(cls.is_type_finalized()); | 2495 ASSERT(cls.is_type_finalized()); |
| 2457 if (cls.is_finalized()) { | 2496 if (cls.is_finalized()) { |
| 2458 return; | 2497 return; |
| (...skipping 886 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3345 ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields()); | 3384 ASSERT(fields_array.Length() == ByteBuffer::NumberOfFields()); |
| 3346 field ^= fields_array.At(0); | 3385 field ^= fields_array.At(0); |
| 3347 ASSERT(field.Offset() == ByteBuffer::data_offset()); | 3386 ASSERT(field.Offset() == ByteBuffer::data_offset()); |
| 3348 name ^= field.name(); | 3387 name ^= field.name(); |
| 3349 expected_name ^= String::New("_data"); | 3388 expected_name ^= String::New("_data"); |
| 3350 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); | 3389 ASSERT(String::EqualsIgnoringPrivateKey(name, expected_name)); |
| 3351 #endif | 3390 #endif |
| 3352 } | 3391 } |
| 3353 | 3392 |
| 3354 } // namespace dart | 3393 } // namespace dart |
| OLD | NEW |