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

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

Issue 2994283002: [VM-Compiler] Don't inline if we don't have inlining budget enough to fully inline.
Patch Set: Created 3 years, 4 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/flow_graph_inliner.h ('k') | runtime/vm/isolate_reload.cc » ('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) 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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)
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_inliner.h ('k') | runtime/vm/isolate_reload.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698