| 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 reset_fields_(reset_fields), | 53 reset_fields_(reset_fields), |
| 54 changed_(false), | 54 changed_(false), |
| 55 function_count_(0), | 55 function_count_(0), |
| 56 class_count_(0), | 56 class_count_(0), |
| 57 selector_count_(0), | 57 selector_count_(0), |
| 58 dropped_function_count_(0), | 58 dropped_function_count_(0), |
| 59 libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())), | 59 libraries_(GrowableObjectArray::Handle(Z, I->object_store()->libraries())), |
| 60 pending_functions_(GrowableObjectArray::Handle(Z, | 60 pending_functions_(GrowableObjectArray::Handle(Z, |
| 61 GrowableObjectArray::New())), | 61 GrowableObjectArray::New())), |
| 62 collected_closures_(GrowableObjectArray::Handle(Z, I->collected_closures())), | 62 collected_closures_(GrowableObjectArray::Handle(Z, I->collected_closures())), |
| 63 sent_selectors_(Z), | 63 sent_selectors_(), |
| 64 error_(Error::Handle(Z)) { | 64 error_(Error::Handle(Z)) { |
| 65 } | 65 } |
| 66 | 66 |
| 67 | 67 |
| 68 void Precompiler::DoCompileAll( | 68 void Precompiler::DoCompileAll( |
| 69 Dart_QualifiedFunctionName embedder_entry_points[]) { | 69 Dart_QualifiedFunctionName embedder_entry_points[]) { |
| 70 // Drop all existing code so we can use the presence of code as an indicator | 70 // Drop all existing code so we can use the presence of code as an indicator |
| 71 // that we have already looked for the function's callees. | 71 // that we have already looked for the function's callees. |
| 72 ClearAllCode(); | 72 ClearAllCode(); |
| 73 | 73 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 90 class_count_, | 90 class_count_, |
| 91 selector_count_, | 91 selector_count_, |
| 92 dropped_function_count_); | 92 dropped_function_count_); |
| 93 } | 93 } |
| 94 | 94 |
| 95 I->set_compilation_allowed(false); | 95 I->set_compilation_allowed(false); |
| 96 } | 96 } |
| 97 | 97 |
| 98 | 98 |
| 99 void Precompiler::ClearAllCode() { | 99 void Precompiler::ClearAllCode() { |
| 100 Library& lib = Library::Handle(Z); | 100 class CodeCodeFunctionVisitor : public FunctionVisitor { |
| 101 Class& cls = Class::Handle(Z); | 101 void VisitFunction(const Function& function) { |
| 102 Array& functions = Array::Handle(Z); | 102 function.ClearCode(); |
| 103 Function& function = Function::Handle(Z); | |
| 104 | |
| 105 for (intptr_t i = 0; i < libraries_.Length(); i++) { | |
| 106 lib ^= libraries_.At(i); | |
| 107 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 108 while (it.HasNext()) { | |
| 109 cls = it.GetNextClass(); | |
| 110 error_ = cls.EnsureIsFinalized(thread_); | |
| 111 if (!error_.IsNull()) { | |
| 112 Jump(error_); | |
| 113 } | |
| 114 } | 103 } |
| 115 } | 104 }; |
| 116 | 105 CodeCodeFunctionVisitor visitor; |
| 117 for (intptr_t i = 0; i < libraries_.Length(); i++) { | 106 VisitFunctions(&visitor); |
| 118 lib ^= libraries_.At(i); | |
| 119 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | |
| 120 while (it.HasNext()) { | |
| 121 cls = it.GetNextClass(); | |
| 122 functions = cls.functions(); | |
| 123 for (intptr_t i = 0; i < functions.Length(); i++) { | |
| 124 function ^= functions.At(i); | |
| 125 function.ClearCode(); | |
| 126 } | |
| 127 } | |
| 128 } | |
| 129 } | 107 } |
| 130 | 108 |
| 131 | 109 |
| 132 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { | 110 void Precompiler::AddRoots(Dart_QualifiedFunctionName embedder_entry_points[]) { |
| 133 // Note that <rootlibrary>.main is not a root. The appropriate main will be | 111 // Note that <rootlibrary>.main is not a root. The appropriate main will be |
| 134 // discovered through _getMainClosure. | 112 // discovered through _getMainClosure. |
| 135 | 113 |
| 136 AddSelector(Symbols::NoSuchMethod()); | 114 AddSelector(Symbols::NoSuchMethod()); |
| 137 | 115 |
| 138 AddSelector(Symbols::Call()); // For speed, not correctness. | 116 AddSelector(Symbols::Call()); // For speed, not correctness. |
| (...skipping 185 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 324 | 302 |
| 325 | 303 |
| 326 void Precompiler::CleanUp() { | 304 void Precompiler::CleanUp() { |
| 327 I->set_collected_closures(GrowableObjectArray::Handle(Z)); | 305 I->set_collected_closures(GrowableObjectArray::Handle(Z)); |
| 328 | 306 |
| 329 DropUncompiledFunctions(); | 307 DropUncompiledFunctions(); |
| 330 | 308 |
| 331 // TODO(rmacnak): DropEmptyClasses(); | 309 // TODO(rmacnak): DropEmptyClasses(); |
| 332 | 310 |
| 333 BindStaticCalls(); | 311 BindStaticCalls(); |
| 312 |
| 313 DedupStackmaps(); |
| 334 } | 314 } |
| 335 | 315 |
| 336 | 316 |
| 337 void Precompiler::ProcessFunction(const Function& function) { | 317 void Precompiler::ProcessFunction(const Function& function) { |
| 338 if (!function.HasCode()) { | 318 if (!function.HasCode()) { |
| 339 function_count_++; | 319 function_count_++; |
| 340 | 320 |
| 341 if (FLAG_trace_precompiler) { | 321 if (FLAG_trace_precompiler) { |
| 342 THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n", | 322 THR_Print("Precompiling %" Pd " %s (%" Pd ", %s)\n", |
| 343 function_count_, | 323 function_count_, |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 476 | 456 |
| 477 pending_functions_.Add(function); | 457 pending_functions_.Add(function); |
| 478 changed_ = true; | 458 changed_ = true; |
| 479 } | 459 } |
| 480 | 460 |
| 481 | 461 |
| 482 bool Precompiler::IsSent(const String& selector) { | 462 bool Precompiler::IsSent(const String& selector) { |
| 483 if (selector.IsNull()) { | 463 if (selector.IsNull()) { |
| 484 return false; | 464 return false; |
| 485 } | 465 } |
| 486 return sent_selectors_.Includes(selector); | 466 return sent_selectors_.Lookup(&selector) != NULL; |
| 487 } | 467 } |
| 488 | 468 |
| 489 | 469 |
| 490 void Precompiler::AddSelector(const String& selector) { | 470 void Precompiler::AddSelector(const String& selector) { |
| 491 ASSERT(!selector.IsNull()); | 471 ASSERT(!selector.IsNull()); |
| 492 | 472 |
| 493 if (!IsSent(selector)) { | 473 if (!IsSent(selector)) { |
| 494 sent_selectors_.Add(selector); | 474 sent_selectors_.Insert(&String::ZoneHandle(Z, selector.raw())); |
| 495 selector_count_++; | 475 selector_count_++; |
| 496 changed_ = true; | 476 changed_ = true; |
| 497 | 477 |
| 498 if (FLAG_trace_precompiler) { | 478 if (FLAG_trace_precompiler) { |
| 499 THR_Print("Enqueueing selector %" Pd " %s\n", | 479 THR_Print("Enqueueing selector %" Pd " %s\n", |
| 500 selector_count_, | 480 selector_count_, |
| 501 selector.ToCString()); | 481 selector.ToCString()); |
| 502 } | 482 } |
| 503 } | 483 } |
| 504 } | 484 } |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 689 function ^= closures.At(j); | 669 function ^= closures.At(j); |
| 690 ASSERT(function.HasCode()); | 670 ASSERT(function.HasCode()); |
| 691 } | 671 } |
| 692 } | 672 } |
| 693 } | 673 } |
| 694 } | 674 } |
| 695 } | 675 } |
| 696 | 676 |
| 697 | 677 |
| 698 void Precompiler::BindStaticCalls() { | 678 void Precompiler::BindStaticCalls() { |
| 679 class BindStaticCallsVisitor : public FunctionVisitor { |
| 680 public: |
| 681 explicit BindStaticCallsVisitor(Zone* zone) : |
| 682 code_(Code::Handle(zone)), |
| 683 table_(Array::Handle(zone)), |
| 684 pc_offset_(Smi::Handle(zone)), |
| 685 target_(Function::Handle(zone)), |
| 686 target_code_(Code::Handle(zone)) { |
| 687 } |
| 688 |
| 689 void VisitFunction(const Function& function) { |
| 690 ASSERT(function.HasCode()); |
| 691 code_ = function.CurrentCode(); |
| 692 table_ = code_.static_calls_target_table(); |
| 693 |
| 694 for (intptr_t i = 0; |
| 695 i < table_.Length(); |
| 696 i += Code::kSCallTableEntryLength) { |
| 697 pc_offset_ ^= table_.At(i + Code::kSCallTableOffsetEntry); |
| 698 target_ ^= table_.At(i + Code::kSCallTableFunctionEntry); |
| 699 if (target_.IsNull()) { |
| 700 target_code_ ^= table_.At(i + Code::kSCallTableCodeEntry); |
| 701 ASSERT(!target_code_.IsNull()); |
| 702 ASSERT(!target_code_.IsFunctionCode()); |
| 703 // Allocation stub or AllocateContext or AllocateArray or ... |
| 704 } else { |
| 705 // Static calls initially call the CallStaticFunction stub because |
| 706 // their target might not be compiled yet. After tree shaking, all |
| 707 // static call targets are compiled. |
| 708 // Cf. runtime entry PatchStaticCall called from CallStaticFunction |
| 709 // stub. |
| 710 ASSERT(target_.HasCode()); |
| 711 target_code_ ^= target_.CurrentCode(); |
| 712 uword pc = pc_offset_.Value() + code_.EntryPoint(); |
| 713 CodePatcher::PatchStaticCallAt(pc, code_, target_code_); |
| 714 } |
| 715 } |
| 716 |
| 717 // We won't patch static calls anymore, so drop the static call table to |
| 718 // save space. |
| 719 code_.set_static_calls_target_table(Object::empty_array()); |
| 720 } |
| 721 |
| 722 private: |
| 723 Code& code_; |
| 724 Array& table_; |
| 725 Smi& pc_offset_; |
| 726 Function& target_; |
| 727 Code& target_code_; |
| 728 }; |
| 729 |
| 730 BindStaticCallsVisitor visitor(Z); |
| 731 VisitFunctions(&visitor); |
| 732 } |
| 733 |
| 734 |
| 735 void Precompiler::DedupStackmaps() { |
| 736 class DedupStackmapsVisitor : public FunctionVisitor { |
| 737 public: |
| 738 explicit DedupStackmapsVisitor(Zone* zone) : |
| 739 zone_(zone), |
| 740 canonical_stackmaps_(), |
| 741 code_(Code::Handle(zone)), |
| 742 stackmaps_(Array::Handle(zone)), |
| 743 stackmap_(Stackmap::Handle(zone)) { |
| 744 } |
| 745 |
| 746 void VisitFunction(const Function& function) { |
| 747 code_ = function.CurrentCode(); |
| 748 stackmaps_ = code_.stackmaps(); |
| 749 if (stackmaps_.IsNull()) return; |
| 750 for (intptr_t i = 0; i < stackmaps_.Length(); i++) { |
| 751 stackmap_ ^= stackmaps_.At(i); |
| 752 stackmap_ = DedupStackmap(stackmap_); |
| 753 stackmaps_.SetAt(i, stackmap_); |
| 754 } |
| 755 } |
| 756 |
| 757 RawStackmap* DedupStackmap(const Stackmap& stackmap) { |
| 758 const Stackmap* canonical_stackmap = |
| 759 canonical_stackmaps_.Lookup(&stackmap); |
| 760 if (canonical_stackmap == NULL) { |
| 761 canonical_stackmaps_.Insert( |
| 762 &Stackmap::ZoneHandle(zone_, stackmap.raw())); |
| 763 return stackmap.raw(); |
| 764 } else { |
| 765 return canonical_stackmap->raw(); |
| 766 } |
| 767 } |
| 768 |
| 769 private: |
| 770 Zone* zone_; |
| 771 StackmapSet canonical_stackmaps_; |
| 772 Code& code_; |
| 773 Array& stackmaps_; |
| 774 Stackmap& stackmap_; |
| 775 }; |
| 776 |
| 777 DedupStackmapsVisitor visitor(Z); |
| 778 VisitFunctions(&visitor); |
| 779 } |
| 780 |
| 781 |
| 782 void Precompiler::VisitFunctions(FunctionVisitor* visitor) { |
| 699 Library& lib = Library::Handle(Z); | 783 Library& lib = Library::Handle(Z); |
| 700 Class& cls = Class::Handle(Z); | 784 Class& cls = Class::Handle(Z); |
| 701 Array& functions = Array::Handle(Z); | 785 Array& functions = Array::Handle(Z); |
| 702 Function& function = Function::Handle(Z); | 786 Function& function = Function::Handle(Z); |
| 703 GrowableObjectArray& closures = GrowableObjectArray::Handle(Z); | 787 GrowableObjectArray& closures = GrowableObjectArray::Handle(Z); |
| 704 | 788 |
| 705 for (intptr_t i = 0; i < libraries_.Length(); i++) { | 789 for (intptr_t i = 0; i < libraries_.Length(); i++) { |
| 706 lib ^= libraries_.At(i); | 790 lib ^= libraries_.At(i); |
| 707 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); | 791 ClassDictionaryIterator it(lib, ClassDictionaryIterator::kIteratePrivate); |
| 708 while (it.HasNext()) { | 792 while (it.HasNext()) { |
| 709 cls = it.GetNextClass(); | 793 cls = it.GetNextClass(); |
| 710 if (cls.IsDynamicClass()) { | 794 if (cls.IsDynamicClass()) { |
| 711 continue; // class 'dynamic' is in the read-only VM isolate. | 795 continue; // class 'dynamic' is in the read-only VM isolate. |
| 712 } | 796 } |
| 713 | 797 |
| 714 functions = cls.functions(); | 798 functions = cls.functions(); |
| 715 for (intptr_t j = 0; j < functions.Length(); j++) { | 799 for (intptr_t j = 0; j < functions.Length(); j++) { |
| 716 function ^= functions.At(j); | 800 function ^= functions.At(j); |
| 717 BindStaticCalls(function); | 801 visitor->VisitFunction(function); |
| 718 } | 802 } |
| 719 | 803 |
| 720 closures = cls.closures(); | 804 closures = cls.closures(); |
| 721 if (!closures.IsNull()) { | 805 if (!closures.IsNull()) { |
| 722 for (intptr_t j = 0; j < closures.Length(); j++) { | 806 for (intptr_t j = 0; j < closures.Length(); j++) { |
| 723 function ^= closures.At(j); | 807 function ^= closures.At(j); |
| 724 BindStaticCalls(function); | 808 visitor->VisitFunction(function); |
| 725 } | 809 } |
| 726 } | 810 } |
| 727 } | 811 } |
| 728 } | 812 } |
| 729 } | 813 } |
| 730 | 814 |
| 731 | |
| 732 void Precompiler::BindStaticCalls(const Function& function) { | |
| 733 ASSERT(function.HasCode()); | |
| 734 | |
| 735 const Code& code = Code::Handle(Z, function.CurrentCode()); | |
| 736 | |
| 737 const Array& table = Array::Handle(Z, code.static_calls_target_table()); | |
| 738 Smi& pc_offset = Smi::Handle(Z); | |
| 739 Function& target = Function::Handle(Z); | |
| 740 Code& target_code = Code::Handle(Z); | |
| 741 | |
| 742 for (intptr_t i = 0; i < table.Length(); i += Code::kSCallTableEntryLength) { | |
| 743 pc_offset ^= table.At(i + Code::kSCallTableOffsetEntry); | |
| 744 target ^= table.At(i + Code::kSCallTableFunctionEntry); | |
| 745 if (target.IsNull()) { | |
| 746 target_code ^= table.At(i + Code::kSCallTableCodeEntry); | |
| 747 ASSERT(!target_code.IsNull()); | |
| 748 ASSERT(!target_code.IsFunctionCode()); | |
| 749 // Allocation stub or AllocateContext or AllocateArray or ... | |
| 750 } else { | |
| 751 // Static calls initially call the CallStaticFunction stub because | |
| 752 // their target might not be compiled yet. After tree shaking, all | |
| 753 // static call targets are compiled. | |
| 754 // Cf. runtime entry PatchStaticCall called from CallStaticFunction stub. | |
| 755 ASSERT(target.HasCode()); | |
| 756 target_code ^= target.CurrentCode(); | |
| 757 CodePatcher::PatchStaticCallAt(pc_offset.Value() + code.EntryPoint(), | |
| 758 code, target_code); | |
| 759 } | |
| 760 } | |
| 761 | |
| 762 // We won't patch static calls anymore, so drop the static call table to save | |
| 763 // space. | |
| 764 code.set_static_calls_target_table(Object::empty_array()); | |
| 765 } | |
| 766 | |
| 767 } // namespace dart | 815 } // namespace dart |
| OLD | NEW |