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 if (!instance.raw()->IsHeapObject()) return; | |
srdjan
2015/10/14 21:04:11
Maybe more readable: if (instance.IsSmi()) return;
rmacnak
2015/10/14 22:22:41
Done.
| |
419 if (!instance.IsCanonical()) return; | |
srdjan
2015/10/14 21:04:11
Add brief comment when that is the case.
rmacnak
2015/10/14 22:22:41
Done.
| |
420 | |
421 class ConstObjectVisitor : public ObjectPointerVisitor { | |
srdjan
2015/10/14 21:04:11
We typically add classes outside the scope of a fu
| |
422 public: | |
423 ConstObjectVisitor(Precompiler* precompiler, Isolate* isolate) : | |
424 ObjectPointerVisitor(isolate), | |
425 precompiler_(precompiler), | |
426 subinstance_(Object::Handle()) {} | |
srdjan
2015/10/14 21:04:11
4 spaces indent.
rmacnak
2015/10/14 22:22:41
Done.
| |
427 | |
428 virtual void VisitPointers(RawObject** first, RawObject** last) { | |
429 for (RawObject** current = first; current <= last; current++) { | |
430 subinstance_ = *current; | |
431 if (subinstance_.IsInstance()) { | |
432 precompiler_->AddConstObject(Instance::Cast(subinstance_)); | |
433 } | |
434 } | |
srdjan
2015/10/14 21:04:11
clear subinstance_ to null (so that it does not ho
rmacnak
2015/10/14 22:22:41
Done.
| |
435 } | |
436 | |
437 private: | |
438 Precompiler* precompiler_; | |
439 Object& subinstance_; | |
440 }; | |
441 | |
442 ConstObjectVisitor visitor(this, I); | |
443 instance.raw()->VisitPointers(&visitor); | |
444 } | |
445 | |
446 | |
413 void Precompiler::AddClosureCall(const ICData& call_site) { | 447 void Precompiler::AddClosureCall(const ICData& call_site) { |
414 const Array& arguments_descriptor = | 448 const Array& arguments_descriptor = |
415 Array::Handle(Z, call_site.arguments_descriptor()); | 449 Array::Handle(Z, call_site.arguments_descriptor()); |
416 const Type& function_impl = | 450 const Type& function_impl = |
417 Type::Handle(Z, I->object_store()->function_impl_type()); | 451 Type::Handle(Z, I->object_store()->function_impl_type()); |
418 const Class& cache_class = | 452 const Class& cache_class = |
419 Class::Handle(Z, function_impl.type_class()); | 453 Class::Handle(Z, function_impl.type_class()); |
420 const Function& dispatcher = Function::Handle(Z, | 454 const Function& dispatcher = Function::Handle(Z, |
421 cache_class.GetInvocationDispatcher(Symbols::Call(), | 455 cache_class.GetInvocationDispatcher(Symbols::Call(), |
422 arguments_descriptor, | 456 arguments_descriptor, |
423 RawFunction::kInvokeFieldDispatcher, | 457 RawFunction::kInvokeFieldDispatcher, |
424 true /* create_if_absent */)); | 458 true /* create_if_absent */)); |
425 AddFunction(dispatcher); | 459 AddFunction(dispatcher); |
426 } | 460 } |
427 | 461 |
428 | 462 |
429 void Precompiler::AddField(const Field& field) { | 463 void Precompiler::AddField(const Field& field) { |
430 if (field.is_static()) { | 464 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()); | 465 const Object& value = Object::Handle(Z, field.StaticValue()); |
434 const Class& cls = Class::Handle(Z, value.clazz()); | 466 if (value.IsInstance()) { |
435 AddClass(cls); | 467 AddConstObject(Instance::Cast(value)); |
468 } | |
436 | 469 |
437 if (field.has_initializer()) { | 470 if (field.has_initializer()) { |
438 // Should not be in the middle of initialization while precompiling. | 471 // Should not be in the middle of initialization while precompiling. |
439 ASSERT(value.raw() != Object::transition_sentinel().raw()); | 472 ASSERT(value.raw() != Object::transition_sentinel().raw()); |
440 | 473 |
441 const bool is_initialized = value.raw() != Object::sentinel().raw(); | 474 const bool is_initialized = value.raw() != Object::sentinel().raw(); |
442 if (is_initialized && !reset_fields_) return; | 475 if (is_initialized && !reset_fields_) return; |
443 | 476 |
444 if (field.HasPrecompiledInitializer()) return; | 477 if (field.HasPrecompiledInitializer()) return; |
445 | 478 |
446 if (FLAG_trace_precompiler) { | 479 if (FLAG_trace_precompiler) { |
447 THR_Print("Precompiling initializer for %s\n", field.ToCString()); | 480 THR_Print("Precompiling initializer for %s\n", field.ToCString()); |
448 } | 481 } |
449 ASSERT(!Dart::IsRunningPrecompiledCode()); | 482 ASSERT(!Dart::IsRunningPrecompiledCode()); |
450 field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue())); | 483 field.SetStaticValue(Instance::Handle(field.SavedInitialStaticValue())); |
451 Compiler::CompileStaticInitializer(field); | 484 Compiler::CompileStaticInitializer(field); |
452 | 485 |
453 const Function& function = | 486 const Function& function = |
454 Function::Handle(Z, field.PrecompiledInitializer()); | 487 Function::Handle(Z, field.PrecompiledInitializer()); |
455 AddCalleesOf(function); | 488 AddCalleesOf(function); |
456 } | 489 } |
457 } | 490 } |
458 } | 491 } |
459 | 492 |
460 | 493 |
461 void Precompiler::AddFunction(const Function& function) { | 494 void Precompiler::AddFunction(const Function& function) { |
462 if (function.HasCode()) return; | 495 if (enqueued_functions_.Lookup(&function) != NULL) return; |
463 | 496 |
497 enqueued_functions_.Insert(&Function::ZoneHandle(Z, function.raw())); | |
464 pending_functions_.Add(function); | 498 pending_functions_.Add(function); |
465 changed_ = true; | 499 changed_ = true; |
466 } | 500 } |
467 | 501 |
468 | 502 |
469 bool Precompiler::IsSent(const String& selector) { | 503 bool Precompiler::IsSent(const String& selector) { |
470 if (selector.IsNull()) { | 504 if (selector.IsNull()) { |
471 return false; | 505 return false; |
472 } | 506 } |
473 return sent_selectors_.Lookup(&selector) != NULL; | 507 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); | 552 String& selector = String::Handle(Z); |
519 String& selector2 = String::Handle(Z); | 553 String& selector2 = String::Handle(Z); |
520 String& selector3 = String::Handle(Z); | 554 String& selector3 = String::Handle(Z); |
521 | 555 |
522 for (intptr_t i = 0; i < libraries_.Length(); i++) { | 556 for (intptr_t i = 0; i < libraries_.Length(); i++) { |
523 lib ^= libraries_.At(i); | 557 lib ^= libraries_.At(i); |
524 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | 558 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
525 while (it.HasNext()) { | 559 while (it.HasNext()) { |
526 cls = it.GetNextClass(); | 560 cls = it.GetNextClass(); |
527 | 561 |
528 if (!cls.is_allocated()) { | 562 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 | 563 |
566 functions = cls.functions(); | 564 functions = cls.functions(); |
567 for (intptr_t k = 0; k < functions.Length(); k++) { | 565 for (intptr_t k = 0; k < functions.Length(); k++) { |
568 function ^= functions.At(k); | 566 function ^= functions.At(k); |
569 | 567 |
570 if (function.is_static() || function.is_abstract()) continue; | 568 if (function.is_static() || function.is_abstract()) continue; |
571 | 569 |
572 // Don't bail out early if there is already code because we may discover | 570 // 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. | 571 // the corresponding getter selector is sent in some later iteration. |
574 // if (function.HasCode()) continue; | 572 // if (function.HasCode()) continue; |
(...skipping 268 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
843 continue; // class 'dynamic' is in the read-only VM isolate. | 841 continue; // class 'dynamic' is in the read-only VM isolate. |
844 } | 842 } |
845 cls.EnsureIsFinalized(T); | 843 cls.EnsureIsFinalized(T); |
846 } | 844 } |
847 } | 845 } |
848 I->set_all_classes_finalized(true); | 846 I->set_all_classes_finalized(true); |
849 } | 847 } |
850 | 848 |
851 | 849 |
852 } // namespace dart | 850 } // namespace dart |
OLD | NEW |