| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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/precompiler.h" | 5 #include "vm/precompiler.h" |
| 6 | 6 |
| 7 #include "vm/code_patcher.h" | 7 #include "vm/code_patcher.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
| 10 #include "vm/log.h" | 10 #include "vm/log.h" |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 53 isolate_(thread->isolate()), | 53 isolate_(thread->isolate()), |
| 54 reset_fields_(reset_fields), | 54 reset_fields_(reset_fields), |
| 55 changed_(false), | 55 changed_(false), |
| 56 function_count_(0), | 56 function_count_(0), |
| 57 class_count_(0), | 57 class_count_(0), |
| 58 selector_count_(0), | 58 selector_count_(0), |
| 59 dropped_function_count_(0), | 59 dropped_function_count_(0), |
| 60 libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())), | 60 libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())), |
| 61 pending_functions_( | 61 pending_functions_( |
| 62 GrowableObjectArray::Handle(Z, GrowableObjectArray::New())), | 62 GrowableObjectArray::Handle(Z, GrowableObjectArray::New())), |
| 63 collected_closures_( | |
| 64 GrowableObjectArray::Handle(Z, GrowableObjectArray::New())), | |
| 65 sent_selectors_(), | 63 sent_selectors_(), |
| 64 enqueued_functions_(), |
| 66 error_(Error::Handle(Z)) { | 65 error_(Error::Handle(Z)) { |
| 67 I->set_collected_closures(collected_closures_); | |
| 68 } | 66 } |
| 69 | 67 |
| 70 | 68 |
| 71 void Precompiler::DoCompileAll( | 69 void Precompiler::DoCompileAll( |
| 72 Dart_QualifiedFunctionName embedder_entry_points[]) { | 70 Dart_QualifiedFunctionName embedder_entry_points[]) { |
| 73 // Drop all existing code so we can use the presence of code as an indicator | |
| 74 // that we have already looked for the function's callees. | |
| 75 ClearAllCode(); | 71 ClearAllCode(); |
| 76 | 72 |
| 77 // Make sure class hierarchy is stable before compilation so that CHA | 73 // Make sure class hierarchy is stable before compilation so that CHA |
| 78 // can be used. | 74 // can be used. Also ensures lookup of entry points won't miss functions |
| 75 // because their class hasn't been finalized yet. |
| 79 FinalizeAllClasses(); | 76 FinalizeAllClasses(); |
| 80 | 77 |
| 81 // Start with the allocations and invocations that happen from C++. | 78 // Start with the allocations and invocations that happen from C++. |
| 82 AddRoots(embedder_entry_points); | 79 AddRoots(embedder_entry_points); |
| 83 | 80 |
| 84 // TODO(rmacnak): Eagerly add field-invocation functions to all signature | |
| 85 // classes so closure calls don't go through the runtime. | |
| 86 | |
| 87 // Compile newly found targets and add their callees until we reach a fixed | 81 // Compile newly found targets and add their callees until we reach a fixed |
| 88 // point. | 82 // point. |
| 89 Iterate(); | 83 Iterate(); |
| 90 | 84 |
| 91 CleanUp(); | 85 DropUncompiledFunctions(); |
| 86 |
| 87 // TODO(rmacnak): DropEmptyClasses(); |
| 88 |
| 89 BindStaticCalls(); |
| 90 |
| 91 DedupStackmaps(); |
| 92 | 92 |
| 93 if (FLAG_trace_precompiler) { | 93 if (FLAG_trace_precompiler) { |
| 94 THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types," | 94 THR_Print("Precompiled %" Pd " functions, %" Pd " dynamic types," |
| 95 " %" Pd " dynamic selectors.\n Dropped %" Pd " functions.\n", | 95 " %" Pd " dynamic selectors.\n Dropped %" Pd " functions.\n", |
| 96 function_count_, | 96 function_count_, |
| 97 class_count_, | 97 class_count_, |
| 98 selector_count_, | 98 selector_count_, |
| 99 dropped_function_count_); | 99 dropped_function_count_); |
| 100 } | 100 } |
| 101 | 101 |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 184 }; | 184 }; |
| 185 | 185 |
| 186 Class& cls = Class::Handle(Z); | 186 Class& cls = Class::Handle(Z); |
| 187 for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) { | 187 for (intptr_t i = 0; kExternallyAllocatedCids[i] != kIllegalCid; i++) { |
| 188 cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]); | 188 cls = isolate()->class_table()->At(kExternallyAllocatedCids[i]); |
| 189 AddClass(cls); | 189 AddClass(cls); |
| 190 } | 190 } |
| 191 | 191 |
| 192 Dart_QualifiedFunctionName vm_entry_points[] = { | 192 Dart_QualifiedFunctionName vm_entry_points[] = { |
| 193 { "dart:async", "::", "_setScheduleImmediateClosure" }, | 193 { "dart:async", "::", "_setScheduleImmediateClosure" }, |
| 194 { "dart:core", "::", "_completeDeferredLoads"}, |
| 194 { "dart:core", "AbstractClassInstantiationError", | 195 { "dart:core", "AbstractClassInstantiationError", |
| 195 "AbstractClassInstantiationError._create" }, | 196 "AbstractClassInstantiationError._create" }, |
| 196 { "dart:core", "ArgumentError", "ArgumentError." }, | 197 { "dart:core", "ArgumentError", "ArgumentError." }, |
| 197 { "dart:core", "AssertionError", "AssertionError." }, | 198 { "dart:core", "AssertionError", "AssertionError." }, |
| 198 { "dart:core", "CyclicInitializationError", | 199 { "dart:core", "CyclicInitializationError", |
| 199 "CyclicInitializationError." }, | 200 "CyclicInitializationError." }, |
| 200 { "dart:core", "FallThroughError", "FallThroughError._create" }, | 201 { "dart:core", "FallThroughError", "FallThroughError._create" }, |
| 201 { "dart:core", "FormatException", "FormatException." }, | 202 { "dart:core", "FormatException", "FormatException." }, |
| 202 { "dart:core", "NoSuchMethodError", "NoSuchMethodError._withType" }, | 203 { "dart:core", "NoSuchMethodError", "NoSuchMethodError._withType" }, |
| 203 { "dart:core", "NullThrownError", "NullThrownError." }, | 204 { "dart:core", "NullThrownError", "NullThrownError." }, |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 290 | 291 |
| 291 while (changed_) { | 292 while (changed_) { |
| 292 changed_ = false; | 293 changed_ = false; |
| 293 | 294 |
| 294 while (pending_functions_.Length() > 0) { | 295 while (pending_functions_.Length() > 0) { |
| 295 function ^= pending_functions_.RemoveLast(); | 296 function ^= pending_functions_.RemoveLast(); |
| 296 ProcessFunction(function); | 297 ProcessFunction(function); |
| 297 } | 298 } |
| 298 | 299 |
| 299 CheckForNewDynamicFunctions(); | 300 CheckForNewDynamicFunctions(); |
| 300 | |
| 301 // Drain collected_closures last because additions to this list come from | |
| 302 // outside the Precompiler and so do not flip our changed_ flag. | |
| 303 while (collected_closures_.Length() > 0) { | |
| 304 function ^= collected_closures_.RemoveLast(); | |
| 305 ProcessFunction(function); | |
| 306 } | |
| 307 } | 301 } |
| 308 } | 302 } |
| 309 | 303 |
| 310 | 304 |
| 311 void Precompiler::CleanUp() { | |
| 312 I->set_collected_closures(GrowableObjectArray::Handle(Z)); | |
| 313 | |
| 314 DropUncompiledFunctions(); | |
| 315 | |
| 316 // TODO(rmacnak): DropEmptyClasses(); | |
| 317 | |
| 318 BindStaticCalls(); | |
| 319 | |
| 320 DedupStackmaps(); | |
| 321 } | |
| 322 | |
| 323 | |
| 324 void Precompiler::ProcessFunction(const Function& function) { | 305 void Precompiler::ProcessFunction(const Function& function) { |
| 325 if (!function.HasCode()) { | 306 if (!function.HasCode()) { |
| 326 function_count_++; | 307 function_count_++; |
| 327 | 308 |
| 328 if (FLAG_trace_precompiler) { | 309 if (FLAG_trace_precompiler) { |
| 329 THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n", | 310 THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n", |
| 330 function_count_, | 311 function_count_, |
| 331 function.ToLibNamePrefixedQualifiedCString(), | 312 function.ToLibNamePrefixedQualifiedCString(), |
| 332 function.token_pos(), | 313 function.token_pos(), |
| 333 Function::KindToCString(function.kind())); | 314 Function::KindToCString(function.kind())); |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 365 | 346 |
| 366 #if defined(TARGET_ARCH_IA32) | 347 #if defined(TARGET_ARCH_IA32) |
| 367 FATAL("Callee scanning unimplemented for IA32"); | 348 FATAL("Callee scanning unimplemented for IA32"); |
| 368 #endif | 349 #endif |
| 369 | 350 |
| 370 const ObjectPool& pool = ObjectPool::Handle(Z, code.GetObjectPool()); | 351 const ObjectPool& pool = ObjectPool::Handle(Z, code.GetObjectPool()); |
| 371 ICData& call_site = ICData::Handle(Z); | 352 ICData& call_site = ICData::Handle(Z); |
| 372 String& selector = String::Handle(Z); | 353 String& selector = String::Handle(Z); |
| 373 Field& field = Field::Handle(Z); | 354 Field& field = Field::Handle(Z); |
| 374 Class& cls = Class::Handle(Z); | 355 Class& cls = Class::Handle(Z); |
| 356 Instance& instance = Instance::Handle(Z); |
| 357 Code& target_code = Code::Handle(Z); |
| 375 for (intptr_t i = 0; i < pool.Length(); i++) { | 358 for (intptr_t i = 0; i < pool.Length(); i++) { |
| 376 if (pool.InfoAt(i) == ObjectPool::kTaggedObject) { | 359 if (pool.InfoAt(i) == ObjectPool::kTaggedObject) { |
| 377 entry = pool.ObjectAt(i); | 360 entry = pool.ObjectAt(i); |
| 378 if (entry.IsICData()) { | 361 if (entry.IsICData()) { |
| 379 call_site ^= entry.raw(); | 362 call_site ^= entry.raw(); |
| 380 if (call_site.NumberOfChecks() == 1) { | 363 if (call_site.NumberOfChecks() == 1) { |
| 381 // Probably a static call. | 364 // Probably a static call. |
| 382 target = call_site.GetTargetAt(0); | 365 target = call_site.GetTargetAt(0); |
| 383 AddFunction(target); | 366 AddFunction(target); |
| 384 if (!target.is_static()) { | 367 if (!target.is_static()) { |
| 385 // Super call (should not enqueue selector) or dynamic call with a | 368 // Super call (should not enqueue selector) or dynamic call with a |
| 386 // CHA prediction (should enqueue selector). | 369 // CHA prediction (should enqueue selector). |
| 387 selector = call_site.target_name(); | 370 selector = call_site.target_name(); |
| 388 AddSelector(selector); | 371 AddSelector(selector); |
| 389 } | 372 } |
| 390 } else { | 373 } else { |
| 391 // A dynamic call. | 374 // A dynamic call. |
| 392 selector = call_site.target_name(); | 375 selector = call_site.target_name(); |
| 393 AddSelector(selector); | 376 AddSelector(selector); |
| 394 if (selector.raw() == Symbols::Call().raw()) { | 377 if (selector.raw() == Symbols::Call().raw()) { |
| 395 // Potential closure call. | 378 // Potential closure call. |
| 396 AddClosureCall(call_site); | 379 AddClosureCall(call_site); |
| 397 } | 380 } |
| 398 } | 381 } |
| 399 } else if (entry.IsField()) { | 382 } else if (entry.IsField()) { |
| 400 // Potential need for field initializer. | 383 // Potential need for field initializer. |
| 401 field ^= entry.raw(); | 384 field ^= entry.raw(); |
| 402 AddField(field); | 385 AddField(field); |
| 403 } else if (entry.IsInstance()) { | 386 } else if (entry.IsInstance()) { |
| 404 // Potential const object. | 387 // Const object, literal or args descriptor. |
| 405 cls = entry.clazz(); | 388 instance ^= entry.raw(); |
| 406 AddClass(cls); | 389 AddConstObject(instance); |
| 390 } else if (entry.IsFunction()) { |
| 391 // Local closure function. |
| 392 target ^= entry.raw(); |
| 393 AddFunction(target); |
| 394 } else if (entry.IsCode()) { |
| 395 target_code ^= entry.raw(); |
| 396 if (target_code.IsAllocationStubCode()) { |
| 397 cls ^= target_code.owner(); |
| 398 AddClass(cls); |
| 399 } |
| 407 } | 400 } |
| 408 } | 401 } |
| 409 } | 402 } |
| 410 } | 403 } |
| 411 | 404 |
| 412 | 405 |
| 406 void Precompiler::AddConstObject(const Instance& instance) { |
| 407 const Class& cls = Class::Handle(Z, instance.clazz()); |
| 408 AddClass(cls); |
| 409 |
| 410 if (instance.IsClosure()) { |
| 411 // An implicit static closure. |
| 412 const Function& func = Function::Handle(Z, Closure::function(instance)); |
| 413 ASSERT(func.is_static()); |
| 414 AddFunction(func); |
| 415 return; |
| 416 } |
| 417 |
| 418 // Can't ask immediate objects if they're canoncial. |
| 419 if (instance.IsSmi()) return; |
| 420 |
| 421 // Some Instances in the ObjectPool aren't const objects, such as |
| 422 // argument descriptors. |
| 423 if (!instance.IsCanonical()) return; |
| 424 |
| 425 class ConstObjectVisitor : public ObjectPointerVisitor { |
| 426 public: |
| 427 ConstObjectVisitor(Precompiler* precompiler, Isolate* isolate) : |
| 428 ObjectPointerVisitor(isolate), |
| 429 precompiler_(precompiler), |
| 430 subinstance_(Object::Handle()) {} |
| 431 |
| 432 virtual void VisitPointers(RawObject** first, RawObject** last) { |
| 433 for (RawObject** current = first; current <= last; current++) { |
| 434 subinstance_ = *current; |
| 435 if (subinstance_.IsInstance()) { |
| 436 precompiler_->AddConstObject(Instance::Cast(subinstance_)); |
| 437 } |
| 438 } |
| 439 subinstance_ = Object::null(); |
| 440 } |
| 441 |
| 442 private: |
| 443 Precompiler* precompiler_; |
| 444 Object& subinstance_; |
| 445 }; |
| 446 |
| 447 ConstObjectVisitor visitor(this, I); |
| 448 instance.raw()->VisitPointers(&visitor); |
| 449 } |
| 450 |
| 451 |
| 413 void Precompiler::AddClosureCall(const ICData& call_site) { | 452 void Precompiler::AddClosureCall(const ICData& call_site) { |
| 414 const Array& arguments_descriptor = | 453 const Array& arguments_descriptor = |
| 415 Array::Handle(Z, call_site.arguments_descriptor()); | 454 Array::Handle(Z, call_site.arguments_descriptor()); |
| 416 const Type& function_impl = | 455 const Type& function_impl = |
| 417 Type::Handle(Z, I->object_store()->function_impl_type()); | 456 Type::Handle(Z, I->object_store()->function_impl_type()); |
| 418 const Class& cache_class = | 457 const Class& cache_class = |
| 419 Class::Handle(Z, function_impl.type_class()); | 458 Class::Handle(Z, function_impl.type_class()); |
| 420 const Function& dispatcher = Function::Handle(Z, | 459 const Function& dispatcher = Function::Handle(Z, |
| 421 cache_class.GetInvocationDispatcher(Symbols::Call(), | 460 cache_class.GetInvocationDispatcher(Symbols::Call(), |
| 422 arguments_descriptor, | 461 arguments_descriptor, |
| 423 RawFunction::kInvokeFieldDispatcher, | 462 RawFunction::kInvokeFieldDispatcher, |
| 424 true /* create_if_absent */)); | 463 true /* create_if_absent */)); |
| 425 AddFunction(dispatcher); | 464 AddFunction(dispatcher); |
| 426 } | 465 } |
| 427 | 466 |
| 428 | 467 |
| 429 void Precompiler::AddField(const Field& field) { | 468 void Precompiler::AddField(const Field& field) { |
| 430 if (field.is_static()) { | 469 if (field.is_static()) { |
| 431 // Potential const object. Uninitialized field will harmlessly do a | |
| 432 // redundant add of the Null class. | |
| 433 const Object& value = Object::Handle(Z, field.StaticValue()); | 470 const Object& value = Object::Handle(Z, field.StaticValue()); |
| 434 const Class& cls = Class::Handle(Z, value.clazz()); | 471 if (value.IsInstance()) { |
| 435 AddClass(cls); | 472 AddConstObject(Instance::Cast(value)); |
| 473 } |
| 436 | 474 |
| 437 if (field.has_initializer()) { | 475 if (field.has_initializer()) { |
| 438 // Should not be in the middle of initialization while precompiling. | 476 // Should not be in the middle of initialization while precompiling. |
| 439 ASSERT(value.raw() != Object::transition_sentinel().raw()); | 477 ASSERT(value.raw() != Object::transition_sentinel().raw()); |
| 440 | 478 |
| 441 const bool is_initialized = value.raw() != Object::sentinel().raw(); | 479 const bool is_initialized = value.raw() != Object::sentinel().raw(); |
| 442 if (is_initialized && !reset_fields_) return; | 480 if (is_initialized && !reset_fields_) return; |
| 443 | 481 |
| 444 if (field.HasPrecompiledInitializer()) return; | 482 if (field.HasPrecompiledInitializer()) return; |
| 445 | 483 |
| 446 if (FLAG_trace_precompiler) { | 484 if (FLAG_trace_precompiler) { |
| 447 THR_Print("Precompiling initializer for %s\n", field.ToCString()); | 485 THR_Print("Precompiling initializer for %s\n", field.ToCString()); |
| 448 } | 486 } |
| 449 ASSERT(!Dart::IsRunningPrecompiledCode()); | 487 ASSERT(!Dart::IsRunningPrecompiledCode()); |
| 450 field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue())); | 488 field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue())); |
| 451 Compiler::CompileStaticInitializer(field); | 489 Compiler::CompileStaticInitializer(field); |
| 452 | 490 |
| 453 const Function& function = | 491 const Function& function = |
| 454 Function::Handle(Z, field.PrecompiledInitializer()); | 492 Function::Handle(Z, field.PrecompiledInitializer()); |
| 455 AddCalleesOf(function); | 493 AddCalleesOf(function); |
| 456 } | 494 } |
| 457 } | 495 } |
| 458 } | 496 } |
| 459 | 497 |
| 460 | 498 |
| 461 void Precompiler::AddFunction(const Function& function) { | 499 void Precompiler::AddFunction(const Function& function) { |
| 462 if (function.HasCode()) return; | 500 if (enqueued_functions_.Lookup(&function) != NULL) return; |
| 463 | 501 |
| 502 enqueued_functions_.Insert(&Function::ZoneHandle(Z, function.raw())); |
| 464 pending_functions_.Add(function); | 503 pending_functions_.Add(function); |
| 465 changed_ = true; | 504 changed_ = true; |
| 466 } | 505 } |
| 467 | 506 |
| 468 | 507 |
| 469 bool Precompiler::IsSent(const String& selector) { | 508 bool Precompiler::IsSent(const String& selector) { |
| 470 if (selector.IsNull()) { | 509 if (selector.IsNull()) { |
| 471 return false; | 510 return false; |
| 472 } | 511 } |
| 473 return sent_selectors_.Lookup(&selector) != NULL; | 512 return sent_selectors_.Lookup(&selector) != NULL; |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 518 String& selector = String::Handle(Z); | 557 String& selector = String::Handle(Z); |
| 519 String& selector2 = String::Handle(Z); | 558 String& selector2 = String::Handle(Z); |
| 520 String& selector3 = String::Handle(Z); | 559 String& selector3 = String::Handle(Z); |
| 521 | 560 |
| 522 for (intptr_t i = 0; i < libraries_.Length(); i++) { | 561 for (intptr_t i = 0; i < libraries_.Length(); i++) { |
| 523 lib ^= libraries_.At(i); | 562 lib ^= libraries_.At(i); |
| 524 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | 563 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
| 525 while (it.HasNext()) { | 564 while (it.HasNext()) { |
| 526 cls = it.GetNextClass(); | 565 cls = it.GetNextClass(); |
| 527 | 566 |
| 528 if (!cls.is_allocated()) { | 567 if (!cls.is_allocated()) continue; |
| 529 bool has_compiled_constructor = false; | |
| 530 if (cls.allocation_stub() != Code::null()) { | |
| 531 // Regular objects. | |
| 532 has_compiled_constructor = true; | |
| 533 } else if (cls.is_synthesized_class()) { | |
| 534 // Enums. | |
| 535 has_compiled_constructor = true; | |
| 536 } else { | |
| 537 // Objects only allocated via const constructors, and not stored in a | |
| 538 // static field or code. | |
| 539 // E.g. A in | |
| 540 // class A { | |
| 541 // const A(); | |
| 542 // toString() => "Don't drop me!"; | |
| 543 // } | |
| 544 // class B { | |
| 545 // const a = const A(); | |
| 546 // const B(); | |
| 547 // static const theB = const B(); | |
| 548 // } | |
| 549 // main() => print(B.theB.a); | |
| 550 functions = cls.functions(); | |
| 551 for (intptr_t k = 0; k < functions.Length(); k++) { | |
| 552 function ^= functions.At(k); | |
| 553 if (function.IsGenerativeConstructor() && | |
| 554 function.HasCode()) { | |
| 555 has_compiled_constructor = true; | |
| 556 break; | |
| 557 } | |
| 558 } | |
| 559 } | |
| 560 if (!has_compiled_constructor) { | |
| 561 continue; | |
| 562 } | |
| 563 AddClass(cls); | |
| 564 } | |
| 565 | 568 |
| 566 functions = cls.functions(); | 569 functions = cls.functions(); |
| 567 for (intptr_t k = 0; k < functions.Length(); k++) { | 570 for (intptr_t k = 0; k < functions.Length(); k++) { |
| 568 function ^= functions.At(k); | 571 function ^= functions.At(k); |
| 569 | 572 |
| 570 if (function.is_static() || function.is_abstract()) continue; | 573 if (function.is_static() || function.is_abstract()) continue; |
| 571 | 574 |
| 572 // Don't bail out early if there is already code because we may discover | 575 // Don't bail out early if there is already code because we may discover |
| 573 // the corresponding getter selector is sent in some later iteration. | 576 // the corresponding getter selector is sent in some later iteration. |
| 574 // if (function.HasCode()) continue; | 577 // if (function.HasCode()) continue; |
| (...skipping 234 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 809 while (it.HasNext()) { | 812 while (it.HasNext()) { |
| 810 cls = it.GetNextClass(); | 813 cls = it.GetNextClass(); |
| 811 if (cls.IsDynamicClass()) { | 814 if (cls.IsDynamicClass()) { |
| 812 continue; // class 'dynamic' is in the read-only VM isolate. | 815 continue; // class 'dynamic' is in the read-only VM isolate. |
| 813 } | 816 } |
| 814 | 817 |
| 815 functions = cls.functions(); | 818 functions = cls.functions(); |
| 816 for (intptr_t j = 0; j < functions.Length(); j++) { | 819 for (intptr_t j = 0; j < functions.Length(); j++) { |
| 817 function ^= functions.At(j); | 820 function ^= functions.At(j); |
| 818 visitor->VisitFunction(function); | 821 visitor->VisitFunction(function); |
| 822 if (function.HasImplicitClosureFunction()) { |
| 823 function = function.ImplicitClosureFunction(); |
| 824 visitor->VisitFunction(function); |
| 825 } |
| 819 } | 826 } |
| 820 | 827 |
| 821 closures = cls.closures(); | 828 closures = cls.closures(); |
| 822 if (!closures.IsNull()) { | 829 if (!closures.IsNull()) { |
| 823 for (intptr_t j = 0; j < closures.Length(); j++) { | 830 for (intptr_t j = 0; j < closures.Length(); j++) { |
| 824 function ^= closures.At(j); | 831 function ^= closures.At(j); |
| 825 visitor->VisitFunction(function); | 832 visitor->VisitFunction(function); |
| 826 } | 833 } |
| 827 } | 834 } |
| 828 } | 835 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 843 continue; // class 'dynamic' is in the read-only VM isolate. | 850 continue; // class 'dynamic' is in the read-only VM isolate. |
| 844 } | 851 } |
| 845 cls.EnsureIsFinalized(T); | 852 cls.EnsureIsFinalized(T); |
| 846 } | 853 } |
| 847 } | 854 } |
| 848 I->set_all_classes_finalized(true); | 855 I->set_all_classes_finalized(true); |
| 849 } | 856 } |
| 850 | 857 |
| 851 | 858 |
| 852 } // namespace dart | 859 } // namespace dart |
| OLD | NEW |