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

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

Issue 907093002: Port flow_graph*, disassembler to ISL_Print (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 5 years, 10 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 | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_compiler.cc ('k') | runtime/vm/flow_graph_optimizer.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 #include "vm/flow_graph_inliner.h" 5 #include "vm/flow_graph_inliner.h"
6 6
7 #include "vm/block_scheduler.h" 7 #include "vm/block_scheduler.h"
8 #include "vm/compiler.h" 8 #include "vm/compiler.h"
9 #include "vm/flags.h" 9 #include "vm/flags.h"
10 #include "vm/flow_graph.h" 10 #include "vm/flow_graph.h"
(...skipping 533 matching lines...) Expand 10 before | Expand all | Expand 10 after
544 CallSites sites1(caller_graph_); 544 CallSites sites1(caller_graph_);
545 CallSites sites2(caller_graph_); 545 CallSites sites2(caller_graph_);
546 CallSites* call_sites_temp = NULL; 546 CallSites* call_sites_temp = NULL;
547 collected_call_sites_ = &sites1; 547 collected_call_sites_ = &sites1;
548 inlining_call_sites_ = &sites2; 548 inlining_call_sites_ = &sites2;
549 // Collect initial call sites. 549 // Collect initial call sites.
550 collected_call_sites_->FindCallSites(caller_graph_, 550 collected_call_sites_->FindCallSites(caller_graph_,
551 inlining_depth_, 551 inlining_depth_,
552 &inlined_info_); 552 &inlined_info_);
553 while (collected_call_sites_->HasCalls()) { 553 while (collected_call_sites_->HasCalls()) {
554 TRACE_INLINING(OS::Print(" Depth %" Pd " ----------\n", 554 TRACE_INLINING(ISL_Print(" Depth %" Pd " ----------\n",
555 inlining_depth_)); 555 inlining_depth_));
556 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) { 556 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) {
557 break; 557 break;
558 } 558 }
559 if (FLAG_print_inlining_tree) { 559 if (FLAG_print_inlining_tree) {
560 OS::Print("**Depth % " Pd " calls to inline %" Pd "\n", 560 ISL_Print("**Depth % " Pd " calls to inline %" Pd "\n",
561 inlining_depth_, collected_call_sites_->NumCalls()); 561 inlining_depth_, collected_call_sites_->NumCalls());
562 } 562 }
563 // Swap collected and inlining arrays and clear the new collecting array. 563 // Swap collected and inlining arrays and clear the new collecting array.
564 call_sites_temp = collected_call_sites_; 564 call_sites_temp = collected_call_sites_;
565 collected_call_sites_ = inlining_call_sites_; 565 collected_call_sites_ = inlining_call_sites_;
566 inlining_call_sites_ = call_sites_temp; 566 inlining_call_sites_ = call_sites_temp;
567 collected_call_sites_->Clear(); 567 collected_call_sites_->Clear();
568 // Inline call sites at the current depth. 568 // Inline call sites at the current depth.
569 InlineInstanceCalls(); 569 InlineInstanceCalls();
570 InlineStaticCalls(); 570 InlineStaticCalls();
(...skipping 24 matching lines...) Expand all
595 if (constant != NULL) { 595 if (constant != NULL) {
596 return new(Z) ConstantInstr(constant->value()); 596 return new(Z) ConstantInstr(constant->value());
597 } else { 597 } else {
598 return new(Z) ParameterInstr(i, graph->graph_entry()); 598 return new(Z) ParameterInstr(i, graph->graph_entry());
599 } 599 }
600 } 600 }
601 601
602 bool TryInlining(const Function& function, 602 bool TryInlining(const Function& function,
603 const Array& argument_names, 603 const Array& argument_names,
604 InlinedCallData* call_data) { 604 InlinedCallData* call_data) {
605 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", 605 TRACE_INLINING(ISL_Print(" => %s (deopt count %d)\n",
606 function.ToCString(), 606 function.ToCString(),
607 function.deoptimization_counter())); 607 function.deoptimization_counter()));
608 608
609 // Make a handle for the unoptimized code so that it is not disconnected 609 // Make a handle for the unoptimized code so that it is not disconnected
610 // from the function while we are trying to inline it. 610 // from the function while we are trying to inline it.
611 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); 611 const Code& unoptimized_code = Code::Handle(function.unoptimized_code());
612 // Abort if the inlinable bit on the function is low. 612 // Abort if the inlinable bit on the function is low.
613 if (!function.CanBeInlined()) { 613 if (!function.CanBeInlined()) {
614 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 614 TRACE_INLINING(ISL_Print(" Bailout: not inlinable\n"));
615 PRINT_INLINING_TREE("Not inlinable", 615 PRINT_INLINING_TREE("Not inlinable",
616 &call_data->caller, &function, call_data->call); 616 &call_data->caller, &function, call_data->call);
617 return false; 617 return false;
618 } 618 }
619 619
620 // Abort if this function has deoptimized too much. 620 // Abort if this function has deoptimized too much.
621 if (function.deoptimization_counter() >= 621 if (function.deoptimization_counter() >=
622 FLAG_deoptimization_counter_threshold) { 622 FLAG_deoptimization_counter_threshold) {
623 function.set_is_inlinable(false); 623 function.set_is_inlinable(false);
624 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); 624 TRACE_INLINING(ISL_Print(" Bailout: deoptimization threshold\n"));
625 PRINT_INLINING_TREE("Deoptimization threshold exceeded", 625 PRINT_INLINING_TREE("Deoptimization threshold exceeded",
626 &call_data->caller, &function, call_data->call); 626 &call_data->caller, &function, call_data->call);
627 return false; 627 return false;
628 } 628 }
629 629
630 const char* kNeverInlineAnnotation = "NeverInline"; 630 const char* kNeverInlineAnnotation = "NeverInline";
631 if (FLAG_enable_inlining_annotations && 631 if (FLAG_enable_inlining_annotations &&
632 HasAnnotation(function, kNeverInlineAnnotation)) { 632 HasAnnotation(function, kNeverInlineAnnotation)) {
633 TRACE_INLINING(OS::Print(" Bailout: NeverInline annotation\n")); 633 TRACE_INLINING(ISL_Print(" Bailout: NeverInline annotation\n"));
634 return false; 634 return false;
635 } 635 }
636 636
637 GrowableArray<Value*>* arguments = call_data->arguments; 637 GrowableArray<Value*>* arguments = call_data->arguments;
638 const intptr_t constant_arguments = CountConstants(*arguments); 638 const intptr_t constant_arguments = CountConstants(*arguments);
639 if (!ShouldWeInline(function, 639 if (!ShouldWeInline(function,
640 function.optimized_instruction_count(), 640 function.optimized_instruction_count(),
641 function.optimized_call_site_count(), 641 function.optimized_call_site_count(),
642 constant_arguments)) { 642 constant_arguments)) {
643 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " 643 TRACE_INLINING(ISL_Print(" Bailout: early heuristics with "
644 "code size: %" Pd ", " 644 "code size: %" Pd ", "
645 "call sites: %" Pd ", " 645 "call sites: %" Pd ", "
646 "const args: %" Pd "\n", 646 "const args: %" Pd "\n",
647 function.optimized_instruction_count(), 647 function.optimized_instruction_count(),
648 function.optimized_call_site_count(), 648 function.optimized_call_site_count(),
649 constant_arguments)); 649 constant_arguments));
650 PRINT_INLINING_TREE("Early heuristic", 650 PRINT_INLINING_TREE("Early heuristic",
651 &call_data->caller, &function, call_data->call); 651 &call_data->caller, &function, call_data->call);
652 return false; 652 return false;
653 } 653 }
654 654
655 // Abort if this is a recursive occurrence. 655 // Abort if this is a recursive occurrence.
656 Definition* call = call_data->call; 656 Definition* call = call_data->call;
657 // Added 'volatile' works around a possible GCC 4.9 compiler bug. 657 // Added 'volatile' works around a possible GCC 4.9 compiler bug.
658 volatile bool is_recursive_call = IsCallRecursive(unoptimized_code, call); 658 volatile bool is_recursive_call = IsCallRecursive(unoptimized_code, call);
659 if (is_recursive_call && 659 if (is_recursive_call &&
660 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) { 660 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) {
661 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); 661 TRACE_INLINING(ISL_Print(" Bailout: recursive function\n"));
662 PRINT_INLINING_TREE("Recursive function", 662 PRINT_INLINING_TREE("Recursive function",
663 &call_data->caller, &function, call_data->call); 663 &call_data->caller, &function, call_data->call);
664 return false; 664 return false;
665 } 665 }
666 666
667 // Save and clear deopt id. 667 // Save and clear deopt id.
668 const intptr_t prev_deopt_id = isolate()->deopt_id(); 668 const intptr_t prev_deopt_id = isolate()->deopt_id();
669 isolate()->set_deopt_id(0); 669 isolate()->set_deopt_id(0);
670 // Install bailout jump. 670 // Install bailout jump.
671 LongJumpScope jump; 671 LongJumpScope jump;
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 711
712 // Create a parameter stub for each fixed positional parameter. 712 // Create a parameter stub for each fixed positional parameter.
713 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { 713 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
714 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); 714 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph));
715 } 715 }
716 716
717 // If the callee has optional parameters, rebuild the argument and stub 717 // If the callee has optional parameters, rebuild the argument and stub
718 // arrays so that actual arguments are in one-to-one with the formal 718 // arrays so that actual arguments are in one-to-one with the formal
719 // parameters. 719 // parameters.
720 if (function.HasOptionalParameters()) { 720 if (function.HasOptionalParameters()) {
721 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); 721 TRACE_INLINING(ISL_Print(" adjusting for optional parameters\n"));
722 if (!AdjustForOptionalParameters(*parsed_function, 722 if (!AdjustForOptionalParameters(*parsed_function,
723 argument_names, 723 argument_names,
724 arguments, 724 arguments,
725 param_stubs, 725 param_stubs,
726 callee_graph)) { 726 callee_graph)) {
727 function.set_is_inlinable(false); 727 function.set_is_inlinable(false);
728 TRACE_INLINING(OS::Print(" Bailout: optional arg mismatch\n")); 728 TRACE_INLINING(ISL_Print(" Bailout: optional arg mismatch\n"));
729 PRINT_INLINING_TREE("Optional arg mismatch", 729 PRINT_INLINING_TREE("Optional arg mismatch",
730 &call_data->caller, &function, call_data->call); 730 &call_data->caller, &function, call_data->call);
731 return false; 731 return false;
732 } 732 }
733 } 733 }
734 734
735 // After treating optional parameters the actual/formal count must match. 735 // After treating optional parameters the actual/formal count must match.
736 ASSERT(arguments->length() == function.NumParameters()); 736 ASSERT(arguments->length() == function.NumParameters());
737 ASSERT(param_stubs->length() == callee_graph->parameter_count()); 737 ASSERT(param_stubs->length() == callee_graph->parameter_count());
738 738
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 DEBUG_ASSERT(callee_graph->VerifyUseLists()); 770 DEBUG_ASSERT(callee_graph->VerifyUseLists());
771 771
772 // Optimize (a << b) & c patterns, merge instructions. Must occur before 772 // Optimize (a << b) & c patterns, merge instructions. Must occur before
773 // 'SelectRepresentations' which inserts conversion nodes. 773 // 'SelectRepresentations' which inserts conversion nodes.
774 optimizer.TryOptimizePatterns(); 774 optimizer.TryOptimizePatterns();
775 DEBUG_ASSERT(callee_graph->VerifyUseLists()); 775 DEBUG_ASSERT(callee_graph->VerifyUseLists());
776 } 776 }
777 777
778 if (FLAG_trace_inlining && 778 if (FLAG_trace_inlining &&
779 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { 779 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
780 OS::Print("Callee graph for inlining %s\n", 780 ISL_Print("Callee graph for inlining %s\n",
781 function.ToFullyQualifiedCString()); 781 function.ToFullyQualifiedCString());
782 FlowGraphPrinter printer(*callee_graph); 782 FlowGraphPrinter printer(*callee_graph);
783 printer.PrintBlocks(); 783 printer.PrintBlocks();
784 } 784 }
785 785
786 // Collect information about the call site and caller graph. 786 // Collect information about the call site and caller graph.
787 // TODO(zerny): Do this after CP and dead code elimination. 787 // TODO(zerny): Do this after CP and dead code elimination.
788 intptr_t constants_count = 0; 788 intptr_t constants_count = 0;
789 for (intptr_t i = 0; i < param_stubs->length(); ++i) { 789 for (intptr_t i = 0; i < param_stubs->length(); ++i) {
790 if ((*param_stubs)[i]->IsConstant()) ++constants_count; 790 if ((*param_stubs)[i]->IsConstant()) ++constants_count;
791 } 791 }
792 792
793 FlowGraphInliner::CollectGraphInfo(callee_graph); 793 FlowGraphInliner::CollectGraphInfo(callee_graph);
794 const intptr_t size = function.optimized_instruction_count(); 794 const intptr_t size = function.optimized_instruction_count();
795 const intptr_t call_site_count = function.optimized_call_site_count(); 795 const intptr_t call_site_count = function.optimized_call_site_count();
796 796
797 function.set_optimized_instruction_count(size); 797 function.set_optimized_instruction_count(size);
798 function.set_optimized_call_site_count(call_site_count); 798 function.set_optimized_call_site_count(call_site_count);
799 799
800 // Use heuristics do decide if this call should be inlined. 800 // Use heuristics do decide if this call should be inlined.
801 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { 801 if (!ShouldWeInline(function, size, call_site_count, constants_count)) {
802 // If size is larger than all thresholds, don't consider it again. 802 // If size is larger than all thresholds, don't consider it again.
803 if ((size > FLAG_inlining_size_threshold) && 803 if ((size > FLAG_inlining_size_threshold) &&
804 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && 804 (call_site_count > FLAG_inlining_callee_call_sites_threshold) &&
805 (size > FLAG_inlining_constant_arguments_min_size_threshold) && 805 (size > FLAG_inlining_constant_arguments_min_size_threshold) &&
806 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { 806 (size > FLAG_inlining_constant_arguments_max_size_threshold)) {
807 function.set_is_inlinable(false); 807 function.set_is_inlinable(false);
808 } 808 }
809 isolate()->set_deopt_id(prev_deopt_id); 809 isolate()->set_deopt_id(prev_deopt_id);
810 TRACE_INLINING(OS::Print(" Bailout: heuristics with " 810 TRACE_INLINING(ISL_Print(" Bailout: heuristics with "
811 "code size: %" Pd ", " 811 "code size: %" Pd ", "
812 "call sites: %" Pd ", " 812 "call sites: %" Pd ", "
813 "const args: %" Pd "\n", 813 "const args: %" Pd "\n",
814 size, 814 size,
815 call_site_count, 815 call_site_count,
816 constants_count)); 816 constants_count));
817 PRINT_INLINING_TREE("Heuristic fail", 817 PRINT_INLINING_TREE("Heuristic fail",
818 &call_data->caller, &function, call_data->call); 818 &call_data->caller, &function, call_data->call);
819 return false; 819 return false;
820 } 820 }
(...skipping 29 matching lines...) Expand all
850 } 850 }
851 // When inlined, we add the deferred prefixes of the callee to the 851 // When inlined, we add the deferred prefixes of the callee to the
852 // caller's list of deferred prefixes. 852 // caller's list of deferred prefixes.
853 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); 853 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes());
854 854
855 FlowGraphInliner::SetInliningId(*callee_graph, 855 FlowGraphInliner::SetInliningId(*callee_graph,
856 inliner_->NextInlineId(callee_graph->function())); 856 inliner_->NextInlineId(callee_graph->function()));
857 // We allocate a ZoneHandle for the unoptimized code so that it cannot be 857 // We allocate a ZoneHandle for the unoptimized code so that it cannot be
858 // disconnected from its function during the rest of compilation. 858 // disconnected from its function during the rest of compilation.
859 Code::ZoneHandle(unoptimized_code.raw()); 859 Code::ZoneHandle(unoptimized_code.raw());
860 TRACE_INLINING(OS::Print(" Success\n")); 860 TRACE_INLINING(ISL_Print(" Success\n"));
861 PRINT_INLINING_TREE(NULL, 861 PRINT_INLINING_TREE(NULL,
862 &call_data->caller, &function, call); 862 &call_data->caller, &function, call);
863 return true; 863 return true;
864 } else { 864 } else {
865 Error& error = Error::Handle(); 865 Error& error = Error::Handle();
866 error = isolate()->object_store()->sticky_error(); 866 error = isolate()->object_store()->sticky_error();
867 isolate()->object_store()->clear_sticky_error(); 867 isolate()->object_store()->clear_sticky_error();
868 isolate()->set_deopt_id(prev_deopt_id); 868 isolate()->set_deopt_id(prev_deopt_id);
869 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 869 TRACE_INLINING(ISL_Print(" Bailout: %s\n", error.ToErrorCString()));
870 PRINT_INLINING_TREE("Bailout", 870 PRINT_INLINING_TREE("Bailout",
871 &call_data->caller, &function, call); 871 &call_data->caller, &function, call);
872 return false; 872 return false;
873 } 873 }
874 } 874 }
875 875
876 void PrintInlinedInfo(const Function& top) { 876 void PrintInlinedInfo(const Function& top) {
877 if (inlined_info_.length() > 0) { 877 if (inlined_info_.length() > 0) {
878 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", 878 ISL_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n",
879 top.ToFullyQualifiedCString(), 879 top.ToFullyQualifiedCString(),
880 GrowthFactor(), 880 GrowthFactor(),
881 initial_size_, 881 initial_size_,
882 inlined_size_); 882 inlined_size_);
883 PrintInlinedInfoFor(top, 1); 883 PrintInlinedInfoFor(top, 1);
884 } 884 }
885 } 885 }
886 886
887 private: 887 private:
888 friend class PolymorphicInliner; 888 friend class PolymorphicInliner;
(...skipping 12 matching lines...) Expand all
901 // Print those that were inlined. 901 // Print those that were inlined.
902 for (intptr_t i = 0; i < inlined_info_.length(); i++) { 902 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
903 const InlinedInfo& info = inlined_info_[i]; 903 const InlinedInfo& info = inlined_info_[i];
904 if (info.bailout_reason != NULL) { 904 if (info.bailout_reason != NULL) {
905 continue; 905 continue;
906 } 906 }
907 if ((info.inlined_depth == depth) && 907 if ((info.inlined_depth == depth) &&
908 (info.caller->raw() == caller.raw()) && 908 (info.caller->raw() == caller.raw()) &&
909 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { 909 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) {
910 for (int t = 0; t < depth; t++) { 910 for (int t = 0; t < depth; t++) {
911 OS::Print(" "); 911 ISL_Print(" ");
912 } 912 }
913 OS::Print("%" Pd " %s\n", 913 ISL_Print("%" Pd " %s\n",
914 info.call_instr->GetDeoptId(), 914 info.call_instr->GetDeoptId(),
915 info.inlined->ToQualifiedCString()); 915 info.inlined->ToQualifiedCString());
916 PrintInlinedInfoFor(*info.inlined, depth + 1); 916 PrintInlinedInfoFor(*info.inlined, depth + 1);
917 call_instructions_printed.Add(info.call_instr->GetDeoptId()); 917 call_instructions_printed.Add(info.call_instr->GetDeoptId());
918 } 918 }
919 } 919 }
920 call_instructions_printed.Clear(); 920 call_instructions_printed.Clear();
921 // Print those that were not inlined. 921 // Print those that were not inlined.
922 for (intptr_t i = 0; i < inlined_info_.length(); i++) { 922 for (intptr_t i = 0; i < inlined_info_.length(); i++) {
923 const InlinedInfo& info = inlined_info_[i]; 923 const InlinedInfo& info = inlined_info_[i];
924 if (info.bailout_reason == NULL) { 924 if (info.bailout_reason == NULL) {
925 continue; 925 continue;
926 } 926 }
927 if ((info.inlined_depth == depth) && 927 if ((info.inlined_depth == depth) &&
928 (info.caller->raw() == caller.raw()) && 928 (info.caller->raw() == caller.raw()) &&
929 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { 929 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) {
930 for (int t = 0; t < depth; t++) { 930 for (int t = 0; t < depth; t++) {
931 OS::Print(" "); 931 ISL_Print(" ");
932 } 932 }
933 OS::Print("NO %" Pd " %s - %s\n", 933 ISL_Print("NO %" Pd " %s - %s\n",
934 info.call_instr->GetDeoptId(), 934 info.call_instr->GetDeoptId(),
935 info.inlined->ToQualifiedCString(), 935 info.inlined->ToQualifiedCString(),
936 info.bailout_reason); 936 info.bailout_reason);
937 call_instructions_printed.Add(info.call_instr->GetDeoptId()); 937 call_instructions_printed.Add(info.call_instr->GetDeoptId());
938 } 938 }
939 } 939 }
940 } 940 }
941 941
942 void InlineCall(InlinedCallData* call_data) { 942 void InlineCall(InlinedCallData* call_data) {
943 TimerScope timer(FLAG_compiler_stats, 943 TimerScope timer(FLAG_compiler_stats,
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1023 parsed_function->AllocateVariables(); 1023 parsed_function->AllocateVariables();
1024 return parsed_function; 1024 return parsed_function;
1025 } 1025 }
1026 1026
1027 // Include special handling for List. factory: inlining it is not helpful 1027 // Include special handling for List. factory: inlining it is not helpful
1028 // if the incoming argument is a non-constant value. 1028 // if the incoming argument is a non-constant value.
1029 // TODO(srdjan): Fix inlining of List. factory. 1029 // TODO(srdjan): Fix inlining of List. factory.
1030 void InlineStaticCalls() { 1030 void InlineStaticCalls() {
1031 const GrowableArray<CallSites::StaticCallInfo>& call_info = 1031 const GrowableArray<CallSites::StaticCallInfo>& call_info =
1032 inlining_call_sites_->static_calls(); 1032 inlining_call_sites_->static_calls();
1033 TRACE_INLINING(OS::Print(" Static Calls (%" Pd ")\n", call_info.length())); 1033 TRACE_INLINING(ISL_Print(" Static Calls (%" Pd ")\n", call_info.length()));
1034 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { 1034 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
1035 StaticCallInstr* call = call_info[call_idx].call; 1035 StaticCallInstr* call = call_info[call_idx].call;
1036 if (call->function().name() == Symbols::ListFactory().raw()) { 1036 if (call->function().name() == Symbols::ListFactory().raw()) {
1037 // Inline only if no arguments or a constant was passed. 1037 // Inline only if no arguments or a constant was passed.
1038 ASSERT(call->function().NumImplicitParameters() == 1); 1038 ASSERT(call->function().NumImplicitParameters() == 1);
1039 ASSERT(call->ArgumentCount() <= 2); 1039 ASSERT(call->ArgumentCount() <= 2);
1040 // Arg 0: Instantiator type arguments. 1040 // Arg 0: Instantiator type arguments.
1041 // Arg 1: Length (optional). 1041 // Arg 1: Length (optional).
1042 if ((call->ArgumentCount() == 2) && 1042 if ((call->ArgumentCount() == 2) &&
1043 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { 1043 (!call->PushArgumentAt(1)->value()->BindsToConstant())) {
1044 // Do not inline since a non-constant argument was passed. 1044 // Do not inline since a non-constant argument was passed.
1045 continue; 1045 continue;
1046 } 1046 }
1047 } 1047 }
1048 const Function& target = call->function(); 1048 const Function& target = call->function();
1049 if (!inliner_->AlwaysInline(target) && 1049 if (!inliner_->AlwaysInline(target) &&
1050 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 1050 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
1051 TRACE_INLINING(OS::Print( 1051 TRACE_INLINING(ISL_Print(
1052 " => %s (deopt count %d)\n Bailout: cold %f\n", 1052 " => %s (deopt count %d)\n Bailout: cold %f\n",
1053 target.ToCString(), 1053 target.ToCString(),
1054 target.deoptimization_counter(), 1054 target.deoptimization_counter(),
1055 call_info[call_idx].ratio)); 1055 call_info[call_idx].ratio));
1056 PRINT_INLINING_TREE("Too cold", 1056 PRINT_INLINING_TREE("Too cold",
1057 call_info[call_idx].caller, &call->function(), call); 1057 call_info[call_idx].caller, &call->function(), call);
1058 continue; 1058 continue;
1059 } 1059 }
1060 GrowableArray<Value*> arguments(call->ArgumentCount()); 1060 GrowableArray<Value*> arguments(call->ArgumentCount());
1061 for (int i = 0; i < call->ArgumentCount(); ++i) { 1061 for (int i = 0; i < call->ArgumentCount(); ++i) {
1062 arguments.Add(call->PushArgumentAt(i)->value()); 1062 arguments.Add(call->PushArgumentAt(i)->value());
1063 } 1063 }
1064 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 1064 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
1065 if (TryInlining(call->function(), call->argument_names(), &call_data)) { 1065 if (TryInlining(call->function(), call->argument_names(), &call_data)) {
1066 InlineCall(&call_data); 1066 InlineCall(&call_data);
1067 } 1067 }
1068 } 1068 }
1069 } 1069 }
1070 1070
1071 void InlineClosureCalls() { 1071 void InlineClosureCalls() {
1072 const GrowableArray<CallSites::ClosureCallInfo>& call_info = 1072 const GrowableArray<CallSites::ClosureCallInfo>& call_info =
1073 inlining_call_sites_->closure_calls(); 1073 inlining_call_sites_->closure_calls();
1074 TRACE_INLINING(OS::Print(" Closure Calls (%" Pd ")\n", 1074 TRACE_INLINING(ISL_Print(" Closure Calls (%" Pd ")\n",
1075 call_info.length())); 1075 call_info.length()));
1076 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { 1076 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
1077 ClosureCallInstr* call = call_info[call_idx].call; 1077 ClosureCallInstr* call = call_info[call_idx].call;
1078 // Find the closure of the callee. 1078 // Find the closure of the callee.
1079 ASSERT(call->ArgumentCount() > 0); 1079 ASSERT(call->ArgumentCount() > 0);
1080 Function& target = Function::ZoneHandle(); 1080 Function& target = Function::ZoneHandle();
1081 AllocateObjectInstr* alloc = 1081 AllocateObjectInstr* alloc =
1082 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject(); 1082 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject();
1083 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { 1083 if ((alloc != NULL) && !alloc->closure_function().IsNull()) {
1084 target ^= alloc->closure_function().raw(); 1084 target ^= alloc->closure_function().raw();
1085 ASSERT(target.signature_class() == alloc->cls().raw()); 1085 ASSERT(target.signature_class() == alloc->cls().raw());
1086 } 1086 }
1087 ConstantInstr* constant = 1087 ConstantInstr* constant =
1088 call->ArgumentAt(0)->OriginalDefinition()->AsConstant(); 1088 call->ArgumentAt(0)->OriginalDefinition()->AsConstant();
1089 if ((constant != NULL) && 1089 if ((constant != NULL) &&
1090 constant->value().IsInstance() && 1090 constant->value().IsInstance() &&
1091 Instance::Cast(constant->value()).IsClosure()) { 1091 Instance::Cast(constant->value()).IsClosure()) {
1092 target ^= Closure::function(Instance::Cast(constant->value())); 1092 target ^= Closure::function(Instance::Cast(constant->value()));
1093 } 1093 }
1094 1094
1095 if (target.IsNull()) { 1095 if (target.IsNull()) {
1096 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 1096 TRACE_INLINING(ISL_Print(" Bailout: non-closure operator\n"));
1097 continue; 1097 continue;
1098 } 1098 }
1099 GrowableArray<Value*> arguments(call->ArgumentCount()); 1099 GrowableArray<Value*> arguments(call->ArgumentCount());
1100 for (int i = 0; i < call->ArgumentCount(); ++i) { 1100 for (int i = 0; i < call->ArgumentCount(); ++i) {
1101 arguments.Add(call->PushArgumentAt(i)->value()); 1101 arguments.Add(call->PushArgumentAt(i)->value());
1102 } 1102 }
1103 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); 1103 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller);
1104 if (TryInlining(target, 1104 if (TryInlining(target,
1105 call->argument_names(), 1105 call->argument_names(),
1106 &call_data)) { 1106 &call_data)) {
1107 InlineCall(&call_data); 1107 InlineCall(&call_data);
1108 } 1108 }
1109 } 1109 }
1110 } 1110 }
1111 1111
1112 void InlineInstanceCalls() { 1112 void InlineInstanceCalls() {
1113 const GrowableArray<CallSites::InstanceCallInfo>& call_info = 1113 const GrowableArray<CallSites::InstanceCallInfo>& call_info =
1114 inlining_call_sites_->instance_calls(); 1114 inlining_call_sites_->instance_calls();
1115 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%" Pd ")\n", 1115 TRACE_INLINING(ISL_Print(" Polymorphic Instance Calls (%" Pd ")\n",
1116 call_info.length())); 1116 call_info.length()));
1117 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { 1117 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) {
1118 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; 1118 PolymorphicInstanceCallInstr* call = call_info[call_idx].call;
1119 if (call->with_checks()) { 1119 if (call->with_checks()) {
1120 const Function& cl = *call_info[call_idx].caller; 1120 const Function& cl = *call_info[call_idx].caller;
1121 PolymorphicInliner inliner(this, call, cl); 1121 PolymorphicInliner inliner(this, call, cl);
1122 inliner.Inline(); 1122 inliner.Inline();
1123 continue; 1123 continue;
1124 } 1124 }
1125 1125
1126 const ICData& ic_data = call->ic_data(); 1126 const ICData& ic_data = call->ic_data();
1127 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 1127 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
1128 if (!inliner_->AlwaysInline(target) && 1128 if (!inliner_->AlwaysInline(target) &&
1129 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { 1129 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) {
1130 TRACE_INLINING(OS::Print( 1130 TRACE_INLINING(ISL_Print(
1131 " => %s (deopt count %d)\n Bailout: cold %f\n", 1131 " => %s (deopt count %d)\n Bailout: cold %f\n",
1132 target.ToCString(), 1132 target.ToCString(),
1133 target.deoptimization_counter(), 1133 target.deoptimization_counter(),
1134 call_info[call_idx].ratio)); 1134 call_info[call_idx].ratio));
1135 PRINT_INLINING_TREE("Too cold", 1135 PRINT_INLINING_TREE("Too cold",
1136 call_info[call_idx].caller, &target, call); 1136 call_info[call_idx].caller, &target, call);
1137 continue; 1137 continue;
1138 } 1138 }
1139 GrowableArray<Value*> arguments(call->ArgumentCount()); 1139 GrowableArray<Value*> arguments(call->ArgumentCount());
1140 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { 1140 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) {
(...skipping 640 matching lines...) Expand 10 before | Expand all | Expand 10 after
1781 current->set_inlining_id(inlining_id); 1781 current->set_inlining_id(inlining_id);
1782 } 1782 }
1783 } 1783 }
1784 } 1784 }
1785 1785
1786 1786
1787 bool FlowGraphInliner::AlwaysInline(const Function& function) { 1787 bool FlowGraphInliner::AlwaysInline(const Function& function) {
1788 const char* kAlwaysInlineAnnotation = "AlwaysInline"; 1788 const char* kAlwaysInlineAnnotation = "AlwaysInline";
1789 if (FLAG_enable_inlining_annotations && 1789 if (FLAG_enable_inlining_annotations &&
1790 HasAnnotation(function, kAlwaysInlineAnnotation)) { 1790 HasAnnotation(function, kAlwaysInlineAnnotation)) {
1791 TRACE_INLINING(OS::Print("AlwaysInline annotation for %s\n", 1791 TRACE_INLINING(ISL_Print("AlwaysInline annotation for %s\n",
1792 function.ToCString())); 1792 function.ToCString()));
1793 return true; 1793 return true;
1794 } 1794 }
1795 1795
1796 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || 1796 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() ||
1797 function.IsImplicitSetterFunction() || function.IsSetterFunction()) { 1797 function.IsImplicitSetterFunction() || function.IsSetterFunction()) {
1798 const intptr_t count = function.optimized_instruction_count(); 1798 const intptr_t count = function.optimized_instruction_count();
1799 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { 1799 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) {
1800 return true; 1800 return true;
1801 } 1801 }
1802 } 1802 }
1803 return MethodRecognizer::AlwaysInline(function); 1803 return MethodRecognizer::AlwaysInline(function);
1804 } 1804 }
1805 1805
1806 1806
1807 void FlowGraphInliner::Inline() { 1807 void FlowGraphInliner::Inline() {
1808 // Collect graph info and store it on the function. 1808 // Collect graph info and store it on the function.
1809 // We might later use it for an early bailout from the inlining. 1809 // We might later use it for an early bailout from the inlining.
1810 CollectGraphInfo(flow_graph_); 1810 CollectGraphInfo(flow_graph_);
1811 1811
1812 const Function& top = flow_graph_->function(); 1812 const Function& top = flow_graph_->function();
1813 if ((FLAG_inlining_filter != NULL) && 1813 if ((FLAG_inlining_filter != NULL) &&
1814 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { 1814 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) {
1815 return; 1815 return;
1816 } 1816 }
1817 1817
1818 TRACE_INLINING(OS::Print("Inlining calls in %s\n", top.ToCString())); 1818 TRACE_INLINING(ISL_Print("Inlining calls in %s\n", top.ToCString()));
1819 1819
1820 if (trace_inlining() && 1820 if (trace_inlining() &&
1821 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { 1821 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) {
1822 OS::Print("Before Inlining of %s\n", flow_graph_-> 1822 ISL_Print("Before Inlining of %s\n", flow_graph_->
1823 function().ToFullyQualifiedCString()); 1823 function().ToFullyQualifiedCString());
1824 FlowGraphPrinter printer(*flow_graph_); 1824 FlowGraphPrinter printer(*flow_graph_);
1825 printer.PrintBlocks(); 1825 printer.PrintBlocks();
1826 } 1826 }
1827 1827
1828 CallSiteInliner inliner(this); 1828 CallSiteInliner inliner(this);
1829 inliner.InlineCalls(); 1829 inliner.InlineCalls();
1830 if (FLAG_print_inlining_tree) { 1830 if (FLAG_print_inlining_tree) {
1831 inliner.PrintInlinedInfo(top); 1831 inliner.PrintInlinedInfo(top);
1832 } 1832 }
1833 1833
1834 if (inliner.inlined()) { 1834 if (inliner.inlined()) {
1835 flow_graph_->DiscoverBlocks(); 1835 flow_graph_->DiscoverBlocks();
1836 if (trace_inlining()) { 1836 if (trace_inlining()) {
1837 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); 1837 ISL_Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
1838 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { 1838 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
1839 OS::Print("After Inlining of %s\n", flow_graph_-> 1839 ISL_Print("After Inlining of %s\n", flow_graph_->
1840 function().ToFullyQualifiedCString()); 1840 function().ToFullyQualifiedCString());
1841 FlowGraphPrinter printer(*flow_graph_); 1841 FlowGraphPrinter printer(*flow_graph_);
1842 printer.PrintBlocks(); 1842 printer.PrintBlocks();
1843 } 1843 }
1844 } 1844 }
1845 } 1845 }
1846 } 1846 }
1847 1847
1848 1848
1849 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { 1849 intptr_t FlowGraphInliner::NextInlineId(const Function& function) {
1850 const intptr_t id = inline_id_to_function_->length(); 1850 const intptr_t id = inline_id_to_function_->length();
1851 inline_id_to_function_->Add(&function); 1851 inline_id_to_function_->Add(&function);
1852 return id; 1852 return id;
1853 } 1853 }
1854 1854
1855 1855
1856 } // namespace dart 1856 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler.cc ('k') | runtime/vm/flow_graph_optimizer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698