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

Side by Side Diff: runtime/vm/compiler/backend/inliner.cc

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

Powered by Google App Engine
This is Rietveld 408576698