Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(623)

Side by Side Diff: runtime/vm/precompiler.cc

Issue 1409523003: Trace through const objects instead of spying on flow graph construction to find closure functions.… (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « runtime/vm/precompiler.h ('k') | sdk/lib/core/uri.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « runtime/vm/precompiler.h ('k') | sdk/lib/core/uri.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698