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 #if !defined(DART_PRECOMPILED_RUNTIME) | 5 #if !defined(DART_PRECOMPILED_RUNTIME) |
6 | 6 |
7 #include "vm/compiler/backend/inliner.h" | 7 #include "vm/compiler/backend/inliner.h" |
8 | 8 |
9 #include "vm/compiler/aot/aot_call_specializer.h" | 9 #include "vm/compiler/aot/aot_call_specializer.h" |
10 #include "vm/compiler/aot/precompiler.h" | 10 #include "vm/compiler/aot/precompiler.h" |
(...skipping 438 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
449 | 449 |
450 class CallSiteInliner; | 450 class CallSiteInliner; |
451 | 451 |
452 class PolymorphicInliner : public ValueObject { | 452 class PolymorphicInliner : public ValueObject { |
453 public: | 453 public: |
454 PolymorphicInliner(CallSiteInliner* owner, | 454 PolymorphicInliner(CallSiteInliner* owner, |
455 PolymorphicInstanceCallInstr* call, | 455 PolymorphicInstanceCallInstr* call, |
456 const Function& caller_function, | 456 const Function& caller_function, |
457 intptr_t caller_inlining_id); | 457 intptr_t caller_inlining_id); |
458 | 458 |
459 void Inline(); | 459 bool Inline(); |
460 | 460 |
461 private: | 461 private: |
462 bool CheckInlinedDuplicate(const Function& target); | 462 bool CheckInlinedDuplicate(const Function& target); |
463 bool CheckNonInlinedDuplicate(const Function& target); | 463 bool CheckNonInlinedDuplicate(const Function& target); |
464 | 464 |
465 bool TryInliningPoly(const TargetInfo& target); | 465 bool TryInliningPoly(const TargetInfo& target); |
466 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); | 466 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); |
467 | 467 |
468 TargetEntryInstr* BuildDecisionGraph(); | 468 TargetEntryInstr* BuildDecisionGraph(); |
469 | 469 |
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
613 inlined_info_() {} | 613 inlined_info_() {} |
614 | 614 |
615 FlowGraph* caller_graph() const { return caller_graph_; } | 615 FlowGraph* caller_graph() const { return caller_graph_; } |
616 | 616 |
617 Thread* thread() const { return caller_graph_->thread(); } | 617 Thread* thread() const { return caller_graph_->thread(); } |
618 Isolate* isolate() const { return caller_graph_->isolate(); } | 618 Isolate* isolate() const { return caller_graph_->isolate(); } |
619 Zone* zone() const { return caller_graph_->zone(); } | 619 Zone* zone() const { return caller_graph_->zone(); } |
620 | 620 |
621 bool trace_inlining() const { return inliner_->trace_inlining(); } | 621 bool trace_inlining() const { return inliner_->trace_inlining(); } |
622 | 622 |
| 623 int inlining_depth() { return inlining_depth_; } |
| 624 |
| 625 struct InliningDecision { |
| 626 InliningDecision(bool b, const char* r) : value(b), reason(r) {} |
| 627 bool value; |
| 628 const char* reason; |
| 629 static InliningDecision Yes(const char* reason) { |
| 630 return InliningDecision(true, reason); |
| 631 } |
| 632 static InliningDecision No(const char* reason) { |
| 633 return InliningDecision(false, reason); |
| 634 } |
| 635 }; |
| 636 |
623 // Inlining heuristics based on Cooper et al. 2008. | 637 // Inlining heuristics based on Cooper et al. 2008. |
624 bool ShouldWeInline(const Function& callee, | 638 InliningDecision ShouldWeInline(const Function& callee, |
625 intptr_t instr_count, | 639 intptr_t instr_count, |
626 intptr_t call_site_count, | 640 intptr_t call_site_count, |
627 intptr_t const_arg_count) { | 641 intptr_t const_arg_count) { |
628 if (inliner_->AlwaysInline(callee)) { | 642 if (inliner_->AlwaysInline(callee)) { |
629 return true; | 643 return InliningDecision::Yes("AlwaysInline"); |
630 } | 644 } |
631 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 645 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
632 // Prevent methods becoming humongous and thus slow to compile. | 646 // Prevent methods becoming humongous and thus slow to compile. |
633 return false; | 647 return InliningDecision::No("--inlining-caller-size-threshold"); |
634 } | 648 } |
635 if (const_arg_count > 0) { | 649 if (const_arg_count > 0) { |
636 if (instr_count > FLAG_inlining_constant_arguments_max_size_threshold) { | 650 if (instr_count > FLAG_inlining_constant_arguments_max_size_threshold) { |
637 return false; | 651 return InliningDecision( |
| 652 false, "--inlining-constant-arguments-max-size-threshold"); |
638 } | 653 } |
639 } else if (instr_count > FLAG_inlining_callee_size_threshold) { | 654 } else if (instr_count > FLAG_inlining_callee_size_threshold) { |
640 return false; | 655 return InliningDecision::No("--inlining-callee-size-threshold"); |
| 656 } |
| 657 int callee_inlining_depth = callee.inlining_depth(); |
| 658 if (callee_inlining_depth > 0 && callee_inlining_depth + inlining_depth_ > |
| 659 FLAG_inlining_depth_threshold) { |
| 660 return InliningDecision::No("--inlining-depth-threshold"); |
641 } | 661 } |
642 // 'instr_count' can be 0 if it was not computed yet. | 662 // 'instr_count' can be 0 if it was not computed yet. |
643 if ((instr_count != 0) && (instr_count <= FLAG_inlining_size_threshold)) { | 663 if ((instr_count != 0) && (instr_count <= FLAG_inlining_size_threshold)) { |
644 return true; | 664 return InliningDecision::Yes("--inlining-size-threshold"); |
645 } | 665 } |
646 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { | 666 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { |
647 return true; | 667 return InliningDecision::Yes("--inlining-callee-call-sites-threshold"); |
648 } | 668 } |
649 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 669 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
650 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { | 670 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { |
651 return true; | 671 return InliningDecision(true, |
| 672 "--inlining-constant-arguments-count and " |
| 673 "inlining-constant-arguments-min-size-threshold"); |
652 } | 674 } |
653 return false; | 675 return InliningDecision::No("default"); |
654 } | 676 } |
655 | 677 |
656 void InlineCalls() { | 678 void InlineCalls() { |
657 // If inlining depth is less than one abort. | 679 // If inlining depth is less than one abort. |
658 if (inlining_depth_threshold_ < 1) return; | 680 if (inlining_depth_threshold_ < 1) return; |
659 if (caller_graph_->function().deoptimization_counter() >= | 681 if (caller_graph_->function().deoptimization_counter() >= |
660 FLAG_deoptimization_counter_inlining_threshold) { | 682 FLAG_deoptimization_counter_inlining_threshold) { |
661 return; | 683 return; |
662 } | 684 } |
663 // Create two call site collections to swap between. | 685 // Create two call site collections to swap between. |
(...skipping 14 matching lines...) Expand all Loading... |
678 if (FLAG_print_inlining_tree) { | 700 if (FLAG_print_inlining_tree) { |
679 THR_Print("**Depth % " Pd " calls to inline %" Pd "\n", inlining_depth_, | 701 THR_Print("**Depth % " Pd " calls to inline %" Pd "\n", inlining_depth_, |
680 collected_call_sites_->NumCalls()); | 702 collected_call_sites_->NumCalls()); |
681 } | 703 } |
682 // Swap collected and inlining arrays and clear the new collecting array. | 704 // Swap collected and inlining arrays and clear the new collecting array. |
683 call_sites_temp = collected_call_sites_; | 705 call_sites_temp = collected_call_sites_; |
684 collected_call_sites_ = inlining_call_sites_; | 706 collected_call_sites_ = inlining_call_sites_; |
685 inlining_call_sites_ = call_sites_temp; | 707 inlining_call_sites_ = call_sites_temp; |
686 collected_call_sites_->Clear(); | 708 collected_call_sites_->Clear(); |
687 // Inline call sites at the current depth. | 709 // Inline call sites at the current depth. |
688 InlineInstanceCalls(); | 710 bool inlined_instance = InlineInstanceCalls(); |
689 InlineStaticCalls(); | 711 bool inlined_statics = InlineStaticCalls(); |
690 InlineClosureCalls(); | 712 bool inlined_closures = InlineClosureCalls(); |
691 // Increment the inlining depths. Checked before subsequent inlining. | 713 if (inlined_instance || inlined_statics || inlined_closures) { |
692 ++inlining_depth_; | 714 // Increment the inlining depths. Checked before subsequent inlining. |
693 if (inlined_recursive_call_) { | 715 ++inlining_depth_; |
694 ++inlining_recursion_depth_; | 716 if (inlined_recursive_call_) { |
695 inlined_recursive_call_ = false; | 717 ++inlining_recursion_depth_; |
| 718 inlined_recursive_call_ = false; |
| 719 } |
| 720 thread()->CheckForSafepoint(); |
696 } | 721 } |
697 thread()->CheckForSafepoint(); | |
698 } | 722 } |
699 | 723 |
700 collected_call_sites_ = NULL; | 724 collected_call_sites_ = NULL; |
701 inlining_call_sites_ = NULL; | 725 inlining_call_sites_ = NULL; |
702 } | 726 } |
703 | 727 |
704 bool inlined() const { return inlined_; } | 728 bool inlined() const { return inlined_; } |
705 | 729 |
706 double GrowthFactor() const { | 730 double GrowthFactor() const { |
707 return static_cast<double>(inlined_size_) / | 731 return static_cast<double>(inlined_size_) / |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
744 if (FLAG_precompiled_mode && function.is_intrinsic() && | 768 if (FLAG_precompiled_mode && function.is_intrinsic() && |
745 !inliner_->AlwaysInline(function)) { | 769 !inliner_->AlwaysInline(function)) { |
746 TRACE_INLINING(THR_Print(" Bailout: intrinisic\n")); | 770 TRACE_INLINING(THR_Print(" Bailout: intrinisic\n")); |
747 PRINT_INLINING_TREE("intrinsic", &call_data->caller, &function, | 771 PRINT_INLINING_TREE("intrinsic", &call_data->caller, &function, |
748 call_data->call); | 772 call_data->call); |
749 return false; | 773 return false; |
750 } | 774 } |
751 | 775 |
752 // Do not rely on function type feedback or presence of code to determine | 776 // Do not rely on function type feedback or presence of code to determine |
753 // if a function was compiled. | 777 // if a function was compiled. |
754 if (!FLAG_precompiled_mode && !function.was_compiled()) { | 778 if (!FLAG_precompiled_mode && !function.WasCompiled()) { |
755 TRACE_INLINING(THR_Print(" Bailout: not compiled yet\n")); | 779 TRACE_INLINING(THR_Print(" Bailout: not compiled yet\n")); |
756 PRINT_INLINING_TREE("Not compiled", &call_data->caller, &function, | 780 PRINT_INLINING_TREE("Not compiled", &call_data->caller, &function, |
757 call_data->call); | 781 call_data->call); |
758 return false; | 782 return false; |
759 } | 783 } |
760 | 784 |
761 if ((inliner_->precompiler_ != NULL) && | 785 if ((inliner_->precompiler_ != NULL) && |
762 inliner_->precompiler_->HasFeedback() && | 786 inliner_->precompiler_->HasFeedback() && |
763 (function.usage_counter() <= 0) && !inliner_->AlwaysInline(function)) { | 787 (function.usage_counter() <= 0) && !inliner_->AlwaysInline(function)) { |
764 TRACE_INLINING(THR_Print(" Bailout: not compiled yet\n")); | 788 TRACE_INLINING(THR_Print(" Bailout: not compiled yet\n")); |
(...skipping 23 matching lines...) Expand all Loading... |
788 | 812 |
789 const char* kNeverInlineAnnotation = "NeverInline"; | 813 const char* kNeverInlineAnnotation = "NeverInline"; |
790 if (FLAG_enable_inlining_annotations && | 814 if (FLAG_enable_inlining_annotations && |
791 HasAnnotation(function, kNeverInlineAnnotation)) { | 815 HasAnnotation(function, kNeverInlineAnnotation)) { |
792 TRACE_INLINING(THR_Print(" Bailout: NeverInline annotation\n")); | 816 TRACE_INLINING(THR_Print(" Bailout: NeverInline annotation\n")); |
793 return false; | 817 return false; |
794 } | 818 } |
795 | 819 |
796 GrowableArray<Value*>* arguments = call_data->arguments; | 820 GrowableArray<Value*>* arguments = call_data->arguments; |
797 const intptr_t constant_arguments = CountConstants(*arguments); | 821 const intptr_t constant_arguments = CountConstants(*arguments); |
798 if (!ShouldWeInline(function, function.optimized_instruction_count(), | 822 InliningDecision decision = ShouldWeInline( |
799 function.optimized_call_site_count(), | 823 function, function.optimized_instruction_count(), |
800 constant_arguments)) { | 824 function.optimized_call_site_count(), constant_arguments); |
| 825 if (!decision.value) { |
801 TRACE_INLINING( | 826 TRACE_INLINING( |
802 THR_Print(" Bailout: early heuristics with " | 827 THR_Print(" Bailout: early heuristics (%s) with " |
803 "code size: %" Pd ", " | 828 "code size: %" Pd ", " |
804 "call sites: %" Pd ", " | 829 "call sites: %" Pd ", " |
| 830 "inlining depth of callee: %d, " |
805 "const args: %" Pd "\n", | 831 "const args: %" Pd "\n", |
806 function.optimized_instruction_count(), | 832 decision.reason, function.optimized_instruction_count(), |
807 function.optimized_call_site_count(), constant_arguments)); | 833 function.optimized_call_site_count(), |
| 834 function.inlining_depth(), constant_arguments)); |
808 PRINT_INLINING_TREE("Early heuristic", &call_data->caller, &function, | 835 PRINT_INLINING_TREE("Early heuristic", &call_data->caller, &function, |
809 call_data->call); | 836 call_data->call); |
810 return false; | 837 return false; |
811 } | 838 } |
812 | 839 |
813 // Abort if this is a recursive occurrence. | 840 // Abort if this is a recursive occurrence. |
814 Definition* call = call_data->call; | 841 Definition* call = call_data->call; |
815 // Added 'volatile' works around a possible GCC 4.9 compiler bug. | 842 // Added 'volatile' works around a possible GCC 4.9 compiler bug. |
816 volatile bool is_recursive_call = IsCallRecursive(function, call); | 843 volatile bool is_recursive_call = IsCallRecursive(function, call); |
817 if (is_recursive_call && | 844 if (is_recursive_call && |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1038 // TODO(zerny): Do this after CP and dead code elimination. | 1065 // TODO(zerny): Do this after CP and dead code elimination. |
1039 intptr_t constants_count = 0; | 1066 intptr_t constants_count = 0; |
1040 for (intptr_t i = 0; i < param_stubs->length(); ++i) { | 1067 for (intptr_t i = 0; i < param_stubs->length(); ++i) { |
1041 if ((*param_stubs)[i]->IsConstant()) ++constants_count; | 1068 if ((*param_stubs)[i]->IsConstant()) ++constants_count; |
1042 } | 1069 } |
1043 | 1070 |
1044 FlowGraphInliner::CollectGraphInfo(callee_graph); | 1071 FlowGraphInliner::CollectGraphInfo(callee_graph); |
1045 const intptr_t size = function.optimized_instruction_count(); | 1072 const intptr_t size = function.optimized_instruction_count(); |
1046 const intptr_t call_site_count = function.optimized_call_site_count(); | 1073 const intptr_t call_site_count = function.optimized_call_site_count(); |
1047 | 1074 |
1048 function.set_optimized_instruction_count(size); | |
1049 function.set_optimized_call_site_count(call_site_count); | |
1050 | |
1051 // Use heuristics do decide if this call should be inlined. | 1075 // Use heuristics do decide if this call should be inlined. |
1052 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { | 1076 InliningDecision decision = |
| 1077 ShouldWeInline(function, size, call_site_count, constants_count); |
| 1078 if (!decision.value) { |
1053 // If size is larger than all thresholds, don't consider it again. | 1079 // If size is larger than all thresholds, don't consider it again. |
1054 if ((size > FLAG_inlining_size_threshold) && | 1080 if ((size > FLAG_inlining_size_threshold) && |
1055 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 1081 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
1056 (size > FLAG_inlining_constant_arguments_min_size_threshold) && | 1082 (size > FLAG_inlining_constant_arguments_min_size_threshold) && |
1057 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { | 1083 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { |
1058 function.set_is_inlinable(false); | 1084 function.set_is_inlinable(false); |
1059 } | 1085 } |
1060 thread()->set_deopt_id(prev_deopt_id); | 1086 thread()->set_deopt_id(prev_deopt_id); |
1061 TRACE_INLINING( | 1087 TRACE_INLINING( |
1062 THR_Print(" Bailout: heuristics with " | 1088 THR_Print(" Bailout: heuristics (%s) with " |
1063 "code size: %" Pd ", " | 1089 "code size: %" Pd ", " |
1064 "call sites: %" Pd ", " | 1090 "call sites: %" Pd ", " |
| 1091 "inlining depth of callee: %d, " |
1065 "const args: %" Pd "\n", | 1092 "const args: %" Pd "\n", |
1066 size, call_site_count, constants_count)); | 1093 decision.reason, size, call_site_count, |
| 1094 function.inlining_depth(), constants_count)); |
1067 PRINT_INLINING_TREE("Heuristic fail", &call_data->caller, &function, | 1095 PRINT_INLINING_TREE("Heuristic fail", &call_data->caller, &function, |
1068 call_data->call); | 1096 call_data->call); |
1069 return false; | 1097 return false; |
1070 } | 1098 } |
1071 | 1099 |
1072 // Inline dispatcher methods regardless of the current depth. | 1100 // Inline dispatcher methods regardless of the current depth. |
1073 const intptr_t depth = | 1101 const intptr_t depth = |
1074 function.IsDispatcherOrImplicitAccessor() ? 0 : inlining_depth_; | 1102 function.IsDispatcherOrImplicitAccessor() ? 0 : inlining_depth_; |
1075 collected_call_sites_->FindCallSites(callee_graph, depth, | 1103 collected_call_sites_->FindCallSites(callee_graph, depth, |
1076 &inlined_info_); | 1104 &inlined_info_); |
(...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1252 *in_cache = false; | 1280 *in_cache = false; |
1253 ParsedFunction* parsed_function = | 1281 ParsedFunction* parsed_function = |
1254 new (Z) ParsedFunction(thread(), function); | 1282 new (Z) ParsedFunction(thread(), function); |
1255 if (!UseKernelFrontEndFor(parsed_function)) { | 1283 if (!UseKernelFrontEndFor(parsed_function)) { |
1256 Parser::ParseFunction(parsed_function); | 1284 Parser::ParseFunction(parsed_function); |
1257 parsed_function->AllocateVariables(); | 1285 parsed_function->AllocateVariables(); |
1258 } | 1286 } |
1259 return parsed_function; | 1287 return parsed_function; |
1260 } | 1288 } |
1261 | 1289 |
1262 void InlineStaticCalls() { | 1290 bool InlineStaticCalls() { |
| 1291 bool inlined = false; |
1263 const GrowableArray<CallSites::StaticCallInfo>& call_info = | 1292 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
1264 inlining_call_sites_->static_calls(); | 1293 inlining_call_sites_->static_calls(); |
1265 TRACE_INLINING(THR_Print(" Static Calls (%" Pd ")\n", call_info.length())); | 1294 TRACE_INLINING(THR_Print(" Static Calls (%" Pd ")\n", call_info.length())); |
1266 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1295 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1267 StaticCallInstr* call = call_info[call_idx].call; | 1296 StaticCallInstr* call = call_info[call_idx].call; |
1268 const Function& target = call->function(); | 1297 const Function& target = call->function(); |
1269 if (!inliner_->AlwaysInline(target) && | 1298 if (!inliner_->AlwaysInline(target) && |
1270 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1299 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
1271 if (trace_inlining()) { | 1300 if (trace_inlining()) { |
1272 String& name = String::Handle(target.QualifiedUserVisibleName()); | 1301 String& name = String::Handle(target.QualifiedUserVisibleName()); |
1273 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", | 1302 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", |
1274 name.ToCString(), target.deoptimization_counter(), | 1303 name.ToCString(), target.deoptimization_counter(), |
1275 call_info[call_idx].ratio); | 1304 call_info[call_idx].ratio); |
1276 } | 1305 } |
1277 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), | 1306 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), |
1278 &call->function(), call); | 1307 &call->function(), call); |
1279 continue; | 1308 continue; |
1280 } | 1309 } |
1281 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1310 GrowableArray<Value*> arguments(call->ArgumentCount()); |
1282 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1311 for (int i = 0; i < call->ArgumentCount(); ++i) { |
1283 arguments.Add(call->PushArgumentAt(i)->value()); | 1312 arguments.Add(call->PushArgumentAt(i)->value()); |
1284 } | 1313 } |
1285 InlinedCallData call_data( | 1314 InlinedCallData call_data( |
1286 call, call->FirstArgIndex(), &arguments, call_info[call_idx].caller(), | 1315 call, call->FirstArgIndex(), &arguments, call_info[call_idx].caller(), |
1287 call_info[call_idx].caller_graph->inlining_id()); | 1316 call_info[call_idx].caller_graph->inlining_id()); |
1288 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1317 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
1289 InlineCall(&call_data); | 1318 InlineCall(&call_data); |
| 1319 inlined = true; |
1290 } | 1320 } |
1291 } | 1321 } |
| 1322 return inlined; |
1292 } | 1323 } |
1293 | 1324 |
1294 void InlineClosureCalls() { | 1325 bool InlineClosureCalls() { |
| 1326 bool inlined = false; |
1295 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1327 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
1296 inlining_call_sites_->closure_calls(); | 1328 inlining_call_sites_->closure_calls(); |
1297 TRACE_INLINING( | 1329 TRACE_INLINING( |
1298 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); | 1330 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); |
1299 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1331 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1300 ClosureCallInstr* call = call_info[call_idx].call; | 1332 ClosureCallInstr* call = call_info[call_idx].call; |
1301 // Find the closure of the callee. | 1333 // Find the closure of the callee. |
1302 ASSERT(call->ArgumentCount() > 0); | 1334 ASSERT(call->ArgumentCount() > 0); |
1303 Function& target = Function::ZoneHandle(); | 1335 Function& target = Function::ZoneHandle(); |
1304 AllocateObjectInstr* alloc = | 1336 AllocateObjectInstr* alloc = |
(...skipping 21 matching lines...) Expand all Loading... |
1326 | 1358 |
1327 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1359 GrowableArray<Value*> arguments(call->ArgumentCount()); |
1328 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1360 for (int i = 0; i < call->ArgumentCount(); ++i) { |
1329 arguments.Add(call->PushArgumentAt(i)->value()); | 1361 arguments.Add(call->PushArgumentAt(i)->value()); |
1330 } | 1362 } |
1331 InlinedCallData call_data( | 1363 InlinedCallData call_data( |
1332 call, call->FirstArgIndex(), &arguments, call_info[call_idx].caller(), | 1364 call, call->FirstArgIndex(), &arguments, call_info[call_idx].caller(), |
1333 call_info[call_idx].caller_graph->inlining_id()); | 1365 call_info[call_idx].caller_graph->inlining_id()); |
1334 if (TryInlining(target, call->argument_names(), &call_data)) { | 1366 if (TryInlining(target, call->argument_names(), &call_data)) { |
1335 InlineCall(&call_data); | 1367 InlineCall(&call_data); |
| 1368 inlined = true; |
1336 } | 1369 } |
1337 } | 1370 } |
| 1371 return inlined; |
1338 } | 1372 } |
1339 | 1373 |
1340 void InlineInstanceCalls() { | 1374 bool InlineInstanceCalls() { |
| 1375 bool inlined = false; |
1341 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1376 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
1342 inlining_call_sites_->instance_calls(); | 1377 inlining_call_sites_->instance_calls(); |
1343 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", | 1378 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", |
1344 call_info.length())); | 1379 call_info.length())); |
1345 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1380 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1346 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1381 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
1347 // PolymorphicInliner introduces deoptimization paths. | 1382 // PolymorphicInliner introduces deoptimization paths. |
1348 if (!call->complete() && !FLAG_polymorphic_with_deopt) { | 1383 if (!call->complete() && !FLAG_polymorphic_with_deopt) { |
1349 TRACE_INLINING( | 1384 TRACE_INLINING( |
1350 THR_Print(" => %s\n Bailout: call with checks\n", | 1385 THR_Print(" => %s\n Bailout: call with checks\n", |
1351 call->instance_call()->function_name().ToCString())); | 1386 call->instance_call()->function_name().ToCString())); |
1352 continue; | 1387 continue; |
1353 } | 1388 } |
1354 const Function& cl = call_info[call_idx].caller(); | 1389 const Function& cl = call_info[call_idx].caller(); |
1355 intptr_t caller_inlining_id = | 1390 intptr_t caller_inlining_id = |
1356 call_info[call_idx].caller_graph->inlining_id(); | 1391 call_info[call_idx].caller_graph->inlining_id(); |
1357 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1392 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
1358 inliner.Inline(); | 1393 if (inliner.Inline()) inlined = true; |
1359 } | 1394 } |
| 1395 return inlined; |
1360 } | 1396 } |
1361 | 1397 |
1362 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, | 1398 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, |
1363 intptr_t first_arg_index, | 1399 intptr_t first_arg_index, |
1364 const Array& argument_names, | 1400 const Array& argument_names, |
1365 GrowableArray<Value*>* arguments, | 1401 GrowableArray<Value*>* arguments, |
1366 ZoneGrowableArray<Definition*>* param_stubs, | 1402 ZoneGrowableArray<Definition*>* param_stubs, |
1367 FlowGraph* callee_graph) { | 1403 FlowGraph* callee_graph) { |
1368 const Function& function = parsed_function.function(); | 1404 const Function& function = parsed_function.function(); |
1369 // The language and this code does not support both optional positional | 1405 // The language and this code does not support both optional positional |
(...skipping 534 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1904 int percent = total == 0 ? 0 : (100 * targets.TargetAt(idx)->count) / total; | 1940 int percent = total == 0 ? 0 : (100 * targets.TargetAt(idx)->count) / total; |
1905 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", | 1941 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", |
1906 name.ToCString(), targets[idx].cid_start, targets[idx].cid_end, | 1942 name.ToCString(), targets[idx].cid_start, targets[idx].cid_end, |
1907 targets.TargetAt(idx)->count, total, percent, message); | 1943 targets.TargetAt(idx)->count, total, percent, message); |
1908 } | 1944 } |
1909 | 1945 |
1910 bool PolymorphicInliner::trace_inlining() const { | 1946 bool PolymorphicInliner::trace_inlining() const { |
1911 return owner_->trace_inlining(); | 1947 return owner_->trace_inlining(); |
1912 } | 1948 } |
1913 | 1949 |
1914 void PolymorphicInliner::Inline() { | 1950 bool PolymorphicInliner::Inline() { |
1915 ASSERT(&variants_ == &call_->targets_); | 1951 ASSERT(&variants_ == &call_->targets_); |
1916 | 1952 |
1917 intptr_t total = call_->total_call_count(); | 1953 intptr_t total = call_->total_call_count(); |
1918 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { | 1954 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { |
1919 TargetInfo* info = variants_.TargetAt(var_idx); | 1955 TargetInfo* info = variants_.TargetAt(var_idx); |
1920 if (variants_.length() > FLAG_max_polymorphic_checks) { | 1956 if (variants_.length() > FLAG_max_polymorphic_checks) { |
1921 non_inlined_variants_->Add(info); | 1957 non_inlined_variants_->Add(info); |
1922 continue; | 1958 continue; |
1923 } | 1959 } |
1924 | 1960 |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1977 TRACE_INLINING(TracePolyInlining(variants_, var_idx, total, "inlined")); | 2013 TRACE_INLINING(TracePolyInlining(variants_, var_idx, total, "inlined")); |
1978 inlined_variants_.Add(&variants_[var_idx]); | 2014 inlined_variants_.Add(&variants_[var_idx]); |
1979 } else { | 2015 } else { |
1980 TRACE_INLINING( | 2016 TRACE_INLINING( |
1981 TracePolyInlining(variants_, var_idx, total, "not inlined")); | 2017 TracePolyInlining(variants_, var_idx, total, "not inlined")); |
1982 non_inlined_variants_->Add(&variants_[var_idx]); | 2018 non_inlined_variants_->Add(&variants_[var_idx]); |
1983 } | 2019 } |
1984 } | 2020 } |
1985 | 2021 |
1986 // If there are no inlined variants, leave the call in place. | 2022 // If there are no inlined variants, leave the call in place. |
1987 if (inlined_variants_.is_empty()) return; | 2023 if (inlined_variants_.is_empty()) return false; |
1988 | 2024 |
1989 // Now build a decision tree (a DAG because of shared inline variants) and | 2025 // Now build a decision tree (a DAG because of shared inline variants) and |
1990 // inline it at the call site. | 2026 // inline it at the call site. |
1991 TargetEntryInstr* entry = BuildDecisionGraph(); | 2027 TargetEntryInstr* entry = BuildDecisionGraph(); |
1992 exit_collector_->ReplaceCall(entry); | 2028 exit_collector_->ReplaceCall(entry); |
1993 } | 2029 return true; |
1994 | |
1995 static uint16_t ClampUint16(intptr_t v) { | |
1996 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); | |
1997 } | 2030 } |
1998 | 2031 |
1999 static bool ShouldTraceInlining(FlowGraph* flow_graph) { | 2032 static bool ShouldTraceInlining(FlowGraph* flow_graph) { |
2000 const Function& top = flow_graph->parsed_function().function(); | 2033 const Function& top = flow_graph->parsed_function().function(); |
2001 return FLAG_trace_inlining && FlowGraphPrinter::ShouldPrint(top); | 2034 return FLAG_trace_inlining && FlowGraphPrinter::ShouldPrint(top); |
2002 } | 2035 } |
2003 | 2036 |
2004 FlowGraphInliner::FlowGraphInliner( | 2037 FlowGraphInliner::FlowGraphInliner( |
2005 FlowGraph* flow_graph, | 2038 FlowGraph* flow_graph, |
2006 GrowableArray<const Function*>* inline_id_to_function, | 2039 GrowableArray<const Function*>* inline_id_to_function, |
(...skipping 12 matching lines...) Expand all Loading... |
2019 precompiler_(precompiler) { | 2052 precompiler_(precompiler) { |
2020 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); | 2053 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
2021 } | 2054 } |
2022 | 2055 |
2023 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { | 2056 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { |
2024 const Function& function = flow_graph->function(); | 2057 const Function& function = flow_graph->function(); |
2025 if (force || (function.optimized_instruction_count() == 0)) { | 2058 if (force || (function.optimized_instruction_count() == 0)) { |
2026 GraphInfoCollector info; | 2059 GraphInfoCollector info; |
2027 info.Collect(*flow_graph); | 2060 info.Collect(*flow_graph); |
2028 | 2061 |
2029 function.set_optimized_instruction_count( | 2062 function.SetOptimizedInstructionCountClamped(info.instruction_count()); |
2030 ClampUint16(info.instruction_count())); | 2063 function.SetOptimizedCallSiteCountClamped(info.call_site_count()); |
2031 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | |
2032 } | 2064 } |
2033 } | 2065 } |
2034 | 2066 |
2035 // TODO(srdjan): This is only needed when disassembling and/or profiling. | 2067 // TODO(srdjan): This is only needed when disassembling and/or profiling. |
2036 // Sets inlining id for all instructions of this flow-graph, as well for the | 2068 // Sets inlining id for all instructions of this flow-graph, as well for the |
2037 // FlowGraph itself. | 2069 // FlowGraph itself. |
2038 void FlowGraphInliner::SetInliningId(FlowGraph* flow_graph, | 2070 void FlowGraphInliner::SetInliningId(FlowGraph* flow_graph, |
2039 intptr_t inlining_id) { | 2071 intptr_t inlining_id) { |
2040 ASSERT(flow_graph->inlining_id() < 0); | 2072 ASSERT(flow_graph->inlining_id() < 0); |
2041 flow_graph->set_inlining_id(inlining_id); | 2073 flow_graph->set_inlining_id(inlining_id); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2083 IsInlineableOperator(function) || | 2115 IsInlineableOperator(function) || |
2084 (function.kind() == RawFunction::kConstructor)) { | 2116 (function.kind() == RawFunction::kConstructor)) { |
2085 const intptr_t count = function.optimized_instruction_count(); | 2117 const intptr_t count = function.optimized_instruction_count(); |
2086 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { | 2118 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
2087 return true; | 2119 return true; |
2088 } | 2120 } |
2089 } | 2121 } |
2090 return MethodRecognizer::AlwaysInline(function); | 2122 return MethodRecognizer::AlwaysInline(function); |
2091 } | 2123 } |
2092 | 2124 |
2093 void FlowGraphInliner::Inline() { | 2125 int FlowGraphInliner::Inline() { |
2094 // Collect graph info and store it on the function. | 2126 // Collect graph info and store it on the function. |
2095 // We might later use it for an early bailout from the inlining. | 2127 // We might later use it for an early bailout from the inlining. |
2096 CollectGraphInfo(flow_graph_); | 2128 CollectGraphInfo(flow_graph_); |
2097 | 2129 |
2098 const Function& top = flow_graph_->function(); | 2130 const Function& top = flow_graph_->function(); |
2099 if ((FLAG_inlining_filter != NULL) && | 2131 if ((FLAG_inlining_filter != NULL) && |
2100 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 2132 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
2101 return; | 2133 return 0; |
2102 } | 2134 } |
2103 | 2135 |
2104 if (trace_inlining()) { | 2136 if (trace_inlining()) { |
2105 String& name = String::Handle(top.QualifiedUserVisibleName()); | 2137 String& name = String::Handle(top.QualifiedUserVisibleName()); |
2106 THR_Print("Inlining calls in %s\n", name.ToCString()); | 2138 THR_Print("Inlining calls in %s\n", name.ToCString()); |
2107 } | 2139 } |
2108 | 2140 |
2109 if (FLAG_support_il_printer && trace_inlining() && | 2141 if (FLAG_support_il_printer && trace_inlining() && |
2110 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 2142 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
2111 THR_Print("Before Inlining of %s\n", | 2143 THR_Print("Before Inlining of %s\n", |
(...skipping 20 matching lines...) Expand all Loading... |
2132 THR_Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 2164 THR_Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
2133 if (FLAG_support_il_printer && | 2165 if (FLAG_support_il_printer && |
2134 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 2166 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
2135 THR_Print("After Inlining of %s\n", | 2167 THR_Print("After Inlining of %s\n", |
2136 flow_graph_->function().ToFullyQualifiedCString()); | 2168 flow_graph_->function().ToFullyQualifiedCString()); |
2137 FlowGraphPrinter printer(*flow_graph_); | 2169 FlowGraphPrinter printer(*flow_graph_); |
2138 printer.PrintBlocks(); | 2170 printer.PrintBlocks(); |
2139 } | 2171 } |
2140 } | 2172 } |
2141 } | 2173 } |
| 2174 return inliner.inlining_depth(); |
2142 } | 2175 } |
2143 | 2176 |
2144 intptr_t FlowGraphInliner::NextInlineId(const Function& function, | 2177 intptr_t FlowGraphInliner::NextInlineId(const Function& function, |
2145 TokenPosition tp, | 2178 TokenPosition tp, |
2146 intptr_t parent_id) { | 2179 intptr_t parent_id) { |
2147 const intptr_t id = inline_id_to_function_->length(); | 2180 const intptr_t id = inline_id_to_function_->length(); |
2148 // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper | 2181 // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper |
2149 // source positions. | 2182 // source positions. |
2150 ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource()); | 2183 ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource()); |
2151 inline_id_to_function_->Add(&function); | 2184 inline_id_to_function_->Add(&function); |
(...skipping 1578 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3730 } | 3763 } |
3731 | 3764 |
3732 default: | 3765 default: |
3733 return false; | 3766 return false; |
3734 } | 3767 } |
3735 } | 3768 } |
3736 | 3769 |
3737 } // namespace dart | 3770 } // namespace dart |
3738 | 3771 |
3739 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3772 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |