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