OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #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 545 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
556 CallSites sites1(caller_graph_); | 556 CallSites sites1(caller_graph_); |
557 CallSites sites2(caller_graph_); | 557 CallSites sites2(caller_graph_); |
558 CallSites* call_sites_temp = NULL; | 558 CallSites* call_sites_temp = NULL; |
559 collected_call_sites_ = &sites1; | 559 collected_call_sites_ = &sites1; |
560 inlining_call_sites_ = &sites2; | 560 inlining_call_sites_ = &sites2; |
561 // Collect initial call sites. | 561 // Collect initial call sites. |
562 collected_call_sites_->FindCallSites(caller_graph_, | 562 collected_call_sites_->FindCallSites(caller_graph_, |
563 inlining_depth_, | 563 inlining_depth_, |
564 &inlined_info_); | 564 &inlined_info_); |
565 while (collected_call_sites_->HasCalls()) { | 565 while (collected_call_sites_->HasCalls()) { |
566 TRACE_INLINING(ISL_Print(" Depth %" Pd " ----------\n", | 566 TRACE_INLINING(THR_Print(" Depth %" Pd " ----------\n", |
567 inlining_depth_)); | 567 inlining_depth_)); |
568 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) { | 568 if (collected_call_sites_->NumCalls() > FLAG_max_inlined_per_depth) { |
569 break; | 569 break; |
570 } | 570 } |
571 if (FLAG_print_inlining_tree) { | 571 if (FLAG_print_inlining_tree) { |
572 ISL_Print("**Depth % " Pd " calls to inline %" Pd "\n", | 572 THR_Print("**Depth % " Pd " calls to inline %" Pd "\n", |
573 inlining_depth_, collected_call_sites_->NumCalls()); | 573 inlining_depth_, collected_call_sites_->NumCalls()); |
574 } | 574 } |
575 // Swap collected and inlining arrays and clear the new collecting array. | 575 // Swap collected and inlining arrays and clear the new collecting array. |
576 call_sites_temp = collected_call_sites_; | 576 call_sites_temp = collected_call_sites_; |
577 collected_call_sites_ = inlining_call_sites_; | 577 collected_call_sites_ = inlining_call_sites_; |
578 inlining_call_sites_ = call_sites_temp; | 578 inlining_call_sites_ = call_sites_temp; |
579 collected_call_sites_->Clear(); | 579 collected_call_sites_->Clear(); |
580 // Inline call sites at the current depth. | 580 // Inline call sites at the current depth. |
581 InlineInstanceCalls(); | 581 InlineInstanceCalls(); |
582 InlineStaticCalls(); | 582 InlineStaticCalls(); |
(...skipping 24 matching lines...) Expand all Loading... |
607 if (constant != NULL) { | 607 if (constant != NULL) { |
608 return new(Z) ConstantInstr(constant->value()); | 608 return new(Z) ConstantInstr(constant->value()); |
609 } else { | 609 } else { |
610 return new(Z) ParameterInstr(i, graph->graph_entry()); | 610 return new(Z) ParameterInstr(i, graph->graph_entry()); |
611 } | 611 } |
612 } | 612 } |
613 | 613 |
614 bool TryInlining(const Function& function, | 614 bool TryInlining(const Function& function, |
615 const Array& argument_names, | 615 const Array& argument_names, |
616 InlinedCallData* call_data) { | 616 InlinedCallData* call_data) { |
617 TRACE_INLINING(ISL_Print(" => %s (deopt count %d)\n", | 617 TRACE_INLINING(THR_Print(" => %s (deopt count %d)\n", |
618 function.ToCString(), | 618 function.ToCString(), |
619 function.deoptimization_counter())); | 619 function.deoptimization_counter())); |
620 | 620 |
621 // Make a handle for the unoptimized code so that it is not disconnected | 621 // Make a handle for the unoptimized code so that it is not disconnected |
622 // from the function while we are trying to inline it. | 622 // from the function while we are trying to inline it. |
623 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 623 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
624 // Abort if the inlinable bit on the function is low. | 624 // Abort if the inlinable bit on the function is low. |
625 if (!function.CanBeInlined()) { | 625 if (!function.CanBeInlined()) { |
626 TRACE_INLINING(ISL_Print(" Bailout: not inlinable\n")); | 626 TRACE_INLINING(THR_Print(" Bailout: not inlinable\n")); |
627 PRINT_INLINING_TREE("Not inlinable", | 627 PRINT_INLINING_TREE("Not inlinable", |
628 &call_data->caller, &function, call_data->call); | 628 &call_data->caller, &function, call_data->call); |
629 return false; | 629 return false; |
630 } | 630 } |
631 | 631 |
632 // Abort if this function has deoptimized too much. | 632 // Abort if this function has deoptimized too much. |
633 if (function.deoptimization_counter() >= | 633 if (function.deoptimization_counter() >= |
634 FLAG_deoptimization_counter_threshold) { | 634 FLAG_deoptimization_counter_threshold) { |
635 function.set_is_inlinable(false); | 635 function.set_is_inlinable(false); |
636 TRACE_INLINING(ISL_Print(" Bailout: deoptimization threshold\n")); | 636 TRACE_INLINING(THR_Print(" Bailout: deoptimization threshold\n")); |
637 PRINT_INLINING_TREE("Deoptimization threshold exceeded", | 637 PRINT_INLINING_TREE("Deoptimization threshold exceeded", |
638 &call_data->caller, &function, call_data->call); | 638 &call_data->caller, &function, call_data->call); |
639 return false; | 639 return false; |
640 } | 640 } |
641 | 641 |
642 const char* kNeverInlineAnnotation = "NeverInline"; | 642 const char* kNeverInlineAnnotation = "NeverInline"; |
643 if (FLAG_enable_inlining_annotations && | 643 if (FLAG_enable_inlining_annotations && |
644 HasAnnotation(function, kNeverInlineAnnotation)) { | 644 HasAnnotation(function, kNeverInlineAnnotation)) { |
645 TRACE_INLINING(ISL_Print(" Bailout: NeverInline annotation\n")); | 645 TRACE_INLINING(THR_Print(" Bailout: NeverInline annotation\n")); |
646 return false; | 646 return false; |
647 } | 647 } |
648 | 648 |
649 GrowableArray<Value*>* arguments = call_data->arguments; | 649 GrowableArray<Value*>* arguments = call_data->arguments; |
650 const intptr_t constant_arguments = CountConstants(*arguments); | 650 const intptr_t constant_arguments = CountConstants(*arguments); |
651 if (!ShouldWeInline(function, | 651 if (!ShouldWeInline(function, |
652 function.optimized_instruction_count(), | 652 function.optimized_instruction_count(), |
653 function.optimized_call_site_count(), | 653 function.optimized_call_site_count(), |
654 constant_arguments)) { | 654 constant_arguments)) { |
655 TRACE_INLINING(ISL_Print(" Bailout: early heuristics with " | 655 TRACE_INLINING(THR_Print(" Bailout: early heuristics with " |
656 "code size: %" Pd ", " | 656 "code size: %" Pd ", " |
657 "call sites: %" Pd ", " | 657 "call sites: %" Pd ", " |
658 "const args: %" Pd "\n", | 658 "const args: %" Pd "\n", |
659 function.optimized_instruction_count(), | 659 function.optimized_instruction_count(), |
660 function.optimized_call_site_count(), | 660 function.optimized_call_site_count(), |
661 constant_arguments)); | 661 constant_arguments)); |
662 PRINT_INLINING_TREE("Early heuristic", | 662 PRINT_INLINING_TREE("Early heuristic", |
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 // Abort if this is a recursive occurrence. | 667 // Abort if this is a recursive occurrence. |
668 Definition* call = call_data->call; | 668 Definition* call = call_data->call; |
669 // Added 'volatile' works around a possible GCC 4.9 compiler bug. | 669 // Added 'volatile' works around a possible GCC 4.9 compiler bug. |
670 volatile bool is_recursive_call = IsCallRecursive(function, call); | 670 volatile bool is_recursive_call = IsCallRecursive(function, call); |
671 if (is_recursive_call && | 671 if (is_recursive_call && |
672 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) { | 672 inlining_recursion_depth_ >= FLAG_inlining_recursion_depth_threshold) { |
673 TRACE_INLINING(ISL_Print(" Bailout: recursive function\n")); | 673 TRACE_INLINING(THR_Print(" Bailout: recursive function\n")); |
674 PRINT_INLINING_TREE("Recursive function", | 674 PRINT_INLINING_TREE("Recursive function", |
675 &call_data->caller, &function, call_data->call); | 675 &call_data->caller, &function, call_data->call); |
676 return false; | 676 return false; |
677 } | 677 } |
678 | 678 |
679 // Save and clear deopt id. | 679 // Save and clear deopt id. |
680 const intptr_t prev_deopt_id = isolate()->deopt_id(); | 680 const intptr_t prev_deopt_id = isolate()->deopt_id(); |
681 isolate()->set_deopt_id(0); | 681 isolate()->set_deopt_id(0); |
682 // Install bailout jump. | 682 // Install bailout jump. |
683 LongJumpScope jump; | 683 LongJumpScope jump; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
726 | 726 |
727 // Create a parameter stub for each fixed positional parameter. | 727 // Create a parameter stub for each fixed positional parameter. |
728 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 728 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
729 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 729 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
730 } | 730 } |
731 | 731 |
732 // If the callee has optional parameters, rebuild the argument and stub | 732 // If the callee has optional parameters, rebuild the argument and stub |
733 // arrays so that actual arguments are in one-to-one with the formal | 733 // arrays so that actual arguments are in one-to-one with the formal |
734 // parameters. | 734 // parameters. |
735 if (function.HasOptionalParameters()) { | 735 if (function.HasOptionalParameters()) { |
736 TRACE_INLINING(ISL_Print(" adjusting for optional parameters\n")); | 736 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); |
737 if (!AdjustForOptionalParameters(*parsed_function, | 737 if (!AdjustForOptionalParameters(*parsed_function, |
738 argument_names, | 738 argument_names, |
739 arguments, | 739 arguments, |
740 param_stubs, | 740 param_stubs, |
741 callee_graph)) { | 741 callee_graph)) { |
742 function.set_is_inlinable(false); | 742 function.set_is_inlinable(false); |
743 TRACE_INLINING(ISL_Print(" Bailout: optional arg mismatch\n")); | 743 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); |
744 PRINT_INLINING_TREE("Optional arg mismatch", | 744 PRINT_INLINING_TREE("Optional arg mismatch", |
745 &call_data->caller, &function, call_data->call); | 745 &call_data->caller, &function, call_data->call); |
746 return false; | 746 return false; |
747 } | 747 } |
748 } | 748 } |
749 | 749 |
750 // After treating optional parameters the actual/formal count must match. | 750 // After treating optional parameters the actual/formal count must match. |
751 ASSERT(arguments->length() == function.NumParameters()); | 751 ASSERT(arguments->length() == function.NumParameters()); |
752 ASSERT(param_stubs->length() == callee_graph->parameter_count()); | 752 ASSERT(param_stubs->length() == callee_graph->parameter_count()); |
753 | 753 |
(...skipping 30 matching lines...) Expand all Loading... |
784 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 784 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
785 | 785 |
786 // Optimize (a << b) & c patterns, merge instructions. Must occur before | 786 // Optimize (a << b) & c patterns, merge instructions. Must occur before |
787 // 'SelectRepresentations' which inserts conversion nodes. | 787 // 'SelectRepresentations' which inserts conversion nodes. |
788 optimizer.TryOptimizePatterns(); | 788 optimizer.TryOptimizePatterns(); |
789 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 789 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
790 } | 790 } |
791 | 791 |
792 if (FLAG_trace_inlining && | 792 if (FLAG_trace_inlining && |
793 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 793 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
794 ISL_Print("Callee graph for inlining %s\n", | 794 THR_Print("Callee graph for inlining %s\n", |
795 function.ToFullyQualifiedCString()); | 795 function.ToFullyQualifiedCString()); |
796 FlowGraphPrinter printer(*callee_graph); | 796 FlowGraphPrinter printer(*callee_graph); |
797 printer.PrintBlocks(); | 797 printer.PrintBlocks(); |
798 } | 798 } |
799 | 799 |
800 // Collect information about the call site and caller graph. | 800 // Collect information about the call site and caller graph. |
801 // TODO(zerny): Do this after CP and dead code elimination. | 801 // TODO(zerny): Do this after CP and dead code elimination. |
802 intptr_t constants_count = 0; | 802 intptr_t constants_count = 0; |
803 for (intptr_t i = 0; i < param_stubs->length(); ++i) { | 803 for (intptr_t i = 0; i < param_stubs->length(); ++i) { |
804 if ((*param_stubs)[i]->IsConstant()) ++constants_count; | 804 if ((*param_stubs)[i]->IsConstant()) ++constants_count; |
805 } | 805 } |
806 | 806 |
807 FlowGraphInliner::CollectGraphInfo(callee_graph); | 807 FlowGraphInliner::CollectGraphInfo(callee_graph); |
808 const intptr_t size = function.optimized_instruction_count(); | 808 const intptr_t size = function.optimized_instruction_count(); |
809 const intptr_t call_site_count = function.optimized_call_site_count(); | 809 const intptr_t call_site_count = function.optimized_call_site_count(); |
810 | 810 |
811 function.set_optimized_instruction_count(size); | 811 function.set_optimized_instruction_count(size); |
812 function.set_optimized_call_site_count(call_site_count); | 812 function.set_optimized_call_site_count(call_site_count); |
813 | 813 |
814 // Use heuristics do decide if this call should be inlined. | 814 // Use heuristics do decide if this call should be inlined. |
815 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { | 815 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { |
816 // If size is larger than all thresholds, don't consider it again. | 816 // If size is larger than all thresholds, don't consider it again. |
817 if ((size > FLAG_inlining_size_threshold) && | 817 if ((size > FLAG_inlining_size_threshold) && |
818 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 818 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
819 (size > FLAG_inlining_constant_arguments_min_size_threshold) && | 819 (size > FLAG_inlining_constant_arguments_min_size_threshold) && |
820 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { | 820 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { |
821 function.set_is_inlinable(false); | 821 function.set_is_inlinable(false); |
822 } | 822 } |
823 isolate()->set_deopt_id(prev_deopt_id); | 823 isolate()->set_deopt_id(prev_deopt_id); |
824 TRACE_INLINING(ISL_Print(" Bailout: heuristics with " | 824 TRACE_INLINING(THR_Print(" Bailout: heuristics with " |
825 "code size: %" Pd ", " | 825 "code size: %" Pd ", " |
826 "call sites: %" Pd ", " | 826 "call sites: %" Pd ", " |
827 "const args: %" Pd "\n", | 827 "const args: %" Pd "\n", |
828 size, | 828 size, |
829 call_site_count, | 829 call_site_count, |
830 constants_count)); | 830 constants_count)); |
831 PRINT_INLINING_TREE("Heuristic fail", | 831 PRINT_INLINING_TREE("Heuristic fail", |
832 &call_data->caller, &function, call_data->call); | 832 &call_data->caller, &function, call_data->call); |
833 return false; | 833 return false; |
834 } | 834 } |
(...skipping 30 matching lines...) Expand all Loading... |
865 // When inlined, we add the deferred prefixes of the callee to the | 865 // When inlined, we add the deferred prefixes of the callee to the |
866 // caller's list of deferred prefixes. | 866 // caller's list of deferred prefixes. |
867 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); | 867 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); |
868 | 868 |
869 FlowGraphInliner::SetInliningId(callee_graph, | 869 FlowGraphInliner::SetInliningId(callee_graph, |
870 inliner_->NextInlineId(callee_graph->function(), | 870 inliner_->NextInlineId(callee_graph->function(), |
871 call_data->caller_inlining_id_)); | 871 call_data->caller_inlining_id_)); |
872 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 872 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
873 // disconnected from its function during the rest of compilation. | 873 // disconnected from its function during the rest of compilation. |
874 Code::ZoneHandle(unoptimized_code.raw()); | 874 Code::ZoneHandle(unoptimized_code.raw()); |
875 TRACE_INLINING(ISL_Print(" Success\n")); | 875 TRACE_INLINING(THR_Print(" Success\n")); |
876 PRINT_INLINING_TREE(NULL, | 876 PRINT_INLINING_TREE(NULL, |
877 &call_data->caller, &function, call); | 877 &call_data->caller, &function, call); |
878 return true; | 878 return true; |
879 } else { | 879 } else { |
880 Error& error = Error::Handle(); | 880 Error& error = Error::Handle(); |
881 error = isolate()->object_store()->sticky_error(); | 881 error = isolate()->object_store()->sticky_error(); |
882 isolate()->object_store()->clear_sticky_error(); | 882 isolate()->object_store()->clear_sticky_error(); |
883 isolate()->set_deopt_id(prev_deopt_id); | 883 isolate()->set_deopt_id(prev_deopt_id); |
884 TRACE_INLINING(ISL_Print(" Bailout: %s\n", error.ToErrorCString())); | 884 TRACE_INLINING(THR_Print(" Bailout: %s\n", error.ToErrorCString())); |
885 PRINT_INLINING_TREE("Bailout", | 885 PRINT_INLINING_TREE("Bailout", |
886 &call_data->caller, &function, call); | 886 &call_data->caller, &function, call); |
887 return false; | 887 return false; |
888 } | 888 } |
889 } | 889 } |
890 | 890 |
891 void PrintInlinedInfo(const Function& top) { | 891 void PrintInlinedInfo(const Function& top) { |
892 if (inlined_info_.length() > 0) { | 892 if (inlined_info_.length() > 0) { |
893 ISL_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", | 893 THR_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", |
894 top.ToFullyQualifiedCString(), | 894 top.ToFullyQualifiedCString(), |
895 GrowthFactor(), | 895 GrowthFactor(), |
896 initial_size_, | 896 initial_size_, |
897 inlined_size_); | 897 inlined_size_); |
898 PrintInlinedInfoFor(top, 1); | 898 PrintInlinedInfoFor(top, 1); |
899 } | 899 } |
900 } | 900 } |
901 | 901 |
902 private: | 902 private: |
903 friend class PolymorphicInliner; | 903 friend class PolymorphicInliner; |
(...skipping 12 matching lines...) Expand all Loading... |
916 // Print those that were inlined. | 916 // Print those that were inlined. |
917 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 917 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
918 const InlinedInfo& info = inlined_info_[i]; | 918 const InlinedInfo& info = inlined_info_[i]; |
919 if (info.bailout_reason != NULL) { | 919 if (info.bailout_reason != NULL) { |
920 continue; | 920 continue; |
921 } | 921 } |
922 if ((info.inlined_depth == depth) && | 922 if ((info.inlined_depth == depth) && |
923 (info.caller->raw() == caller.raw()) && | 923 (info.caller->raw() == caller.raw()) && |
924 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { | 924 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { |
925 for (int t = 0; t < depth; t++) { | 925 for (int t = 0; t < depth; t++) { |
926 ISL_Print(" "); | 926 THR_Print(" "); |
927 } | 927 } |
928 ISL_Print("%" Pd " %s\n", | 928 THR_Print("%" Pd " %s\n", |
929 info.call_instr->GetDeoptId(), | 929 info.call_instr->GetDeoptId(), |
930 info.inlined->ToQualifiedCString()); | 930 info.inlined->ToQualifiedCString()); |
931 PrintInlinedInfoFor(*info.inlined, depth + 1); | 931 PrintInlinedInfoFor(*info.inlined, depth + 1); |
932 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 932 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
933 } | 933 } |
934 } | 934 } |
935 call_instructions_printed.Clear(); | 935 call_instructions_printed.Clear(); |
936 // Print those that were not inlined. | 936 // Print those that were not inlined. |
937 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 937 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
938 const InlinedInfo& info = inlined_info_[i]; | 938 const InlinedInfo& info = inlined_info_[i]; |
939 if (info.bailout_reason == NULL) { | 939 if (info.bailout_reason == NULL) { |
940 continue; | 940 continue; |
941 } | 941 } |
942 if ((info.inlined_depth == depth) && | 942 if ((info.inlined_depth == depth) && |
943 (info.caller->raw() == caller.raw()) && | 943 (info.caller->raw() == caller.raw()) && |
944 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { | 944 !Contains(call_instructions_printed, info.call_instr->GetDeoptId())) { |
945 for (int t = 0; t < depth; t++) { | 945 for (int t = 0; t < depth; t++) { |
946 ISL_Print(" "); | 946 THR_Print(" "); |
947 } | 947 } |
948 ISL_Print("NO %" Pd " %s - %s\n", | 948 THR_Print("NO %" Pd " %s - %s\n", |
949 info.call_instr->GetDeoptId(), | 949 info.call_instr->GetDeoptId(), |
950 info.inlined->ToQualifiedCString(), | 950 info.inlined->ToQualifiedCString(), |
951 info.bailout_reason); | 951 info.bailout_reason); |
952 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 952 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
953 } | 953 } |
954 } | 954 } |
955 } | 955 } |
956 | 956 |
957 void InlineCall(InlinedCallData* call_data) { | 957 void InlineCall(InlinedCallData* call_data) { |
958 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); | 958 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1036 parsed_function->AllocateVariables(); | 1036 parsed_function->AllocateVariables(); |
1037 return parsed_function; | 1037 return parsed_function; |
1038 } | 1038 } |
1039 | 1039 |
1040 // Include special handling for List. factory: inlining it is not helpful | 1040 // Include special handling for List. factory: inlining it is not helpful |
1041 // if the incoming argument is a non-constant value. | 1041 // if the incoming argument is a non-constant value. |
1042 // TODO(srdjan): Fix inlining of List. factory. | 1042 // TODO(srdjan): Fix inlining of List. factory. |
1043 void InlineStaticCalls() { | 1043 void InlineStaticCalls() { |
1044 const GrowableArray<CallSites::StaticCallInfo>& call_info = | 1044 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
1045 inlining_call_sites_->static_calls(); | 1045 inlining_call_sites_->static_calls(); |
1046 TRACE_INLINING(ISL_Print(" Static Calls (%" Pd ")\n", call_info.length())); | 1046 TRACE_INLINING(THR_Print(" Static Calls (%" Pd ")\n", call_info.length())); |
1047 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1047 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1048 StaticCallInstr* call = call_info[call_idx].call; | 1048 StaticCallInstr* call = call_info[call_idx].call; |
1049 if (call->function().name() == Symbols::ListFactory().raw()) { | 1049 if (call->function().name() == Symbols::ListFactory().raw()) { |
1050 // Inline only if no arguments or a constant was passed. | 1050 // Inline only if no arguments or a constant was passed. |
1051 ASSERT(call->function().NumImplicitParameters() == 1); | 1051 ASSERT(call->function().NumImplicitParameters() == 1); |
1052 ASSERT(call->ArgumentCount() <= 2); | 1052 ASSERT(call->ArgumentCount() <= 2); |
1053 // Arg 0: Instantiator type arguments. | 1053 // Arg 0: Instantiator type arguments. |
1054 // Arg 1: Length (optional). | 1054 // Arg 1: Length (optional). |
1055 if ((call->ArgumentCount() == 2) && | 1055 if ((call->ArgumentCount() == 2) && |
1056 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 1056 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
1057 // Do not inline since a non-constant argument was passed. | 1057 // Do not inline since a non-constant argument was passed. |
1058 continue; | 1058 continue; |
1059 } | 1059 } |
1060 } | 1060 } |
1061 const Function& target = call->function(); | 1061 const Function& target = call->function(); |
1062 if (!inliner_->AlwaysInline(target) && | 1062 if (!inliner_->AlwaysInline(target) && |
1063 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1063 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
1064 TRACE_INLINING(ISL_Print( | 1064 TRACE_INLINING(THR_Print( |
1065 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1065 " => %s (deopt count %d)\n Bailout: cold %f\n", |
1066 target.ToCString(), | 1066 target.ToCString(), |
1067 target.deoptimization_counter(), | 1067 target.deoptimization_counter(), |
1068 call_info[call_idx].ratio)); | 1068 call_info[call_idx].ratio)); |
1069 PRINT_INLINING_TREE("Too cold", | 1069 PRINT_INLINING_TREE("Too cold", |
1070 &call_info[call_idx].caller(), &call->function(), call); | 1070 &call_info[call_idx].caller(), &call->function(), call); |
1071 continue; | 1071 continue; |
1072 } | 1072 } |
1073 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1073 GrowableArray<Value*> arguments(call->ArgumentCount()); |
1074 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1074 for (int i = 0; i < call->ArgumentCount(); ++i) { |
1075 arguments.Add(call->PushArgumentAt(i)->value()); | 1075 arguments.Add(call->PushArgumentAt(i)->value()); |
1076 } | 1076 } |
1077 InlinedCallData call_data( | 1077 InlinedCallData call_data( |
1078 call, &arguments, call_info[call_idx].caller(), | 1078 call, &arguments, call_info[call_idx].caller(), |
1079 call_info[call_idx].caller_graph->inlining_id()); | 1079 call_info[call_idx].caller_graph->inlining_id()); |
1080 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1080 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
1081 InlineCall(&call_data); | 1081 InlineCall(&call_data); |
1082 } | 1082 } |
1083 } | 1083 } |
1084 } | 1084 } |
1085 | 1085 |
1086 void InlineClosureCalls() { | 1086 void InlineClosureCalls() { |
1087 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1087 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
1088 inlining_call_sites_->closure_calls(); | 1088 inlining_call_sites_->closure_calls(); |
1089 TRACE_INLINING(ISL_Print(" Closure Calls (%" Pd ")\n", | 1089 TRACE_INLINING(THR_Print(" Closure Calls (%" Pd ")\n", |
1090 call_info.length())); | 1090 call_info.length())); |
1091 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1091 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1092 ClosureCallInstr* call = call_info[call_idx].call; | 1092 ClosureCallInstr* call = call_info[call_idx].call; |
1093 // Find the closure of the callee. | 1093 // Find the closure of the callee. |
1094 ASSERT(call->ArgumentCount() > 0); | 1094 ASSERT(call->ArgumentCount() > 0); |
1095 Function& target = Function::ZoneHandle(); | 1095 Function& target = Function::ZoneHandle(); |
1096 AllocateObjectInstr* alloc = | 1096 AllocateObjectInstr* alloc = |
1097 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject(); | 1097 call->ArgumentAt(0)->OriginalDefinition()->AsAllocateObject(); |
1098 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { | 1098 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { |
1099 target ^= alloc->closure_function().raw(); | 1099 target ^= alloc->closure_function().raw(); |
1100 ASSERT(target.signature_class() == alloc->cls().raw()); | 1100 ASSERT(target.signature_class() == alloc->cls().raw()); |
1101 } | 1101 } |
1102 ConstantInstr* constant = | 1102 ConstantInstr* constant = |
1103 call->ArgumentAt(0)->OriginalDefinition()->AsConstant(); | 1103 call->ArgumentAt(0)->OriginalDefinition()->AsConstant(); |
1104 if ((constant != NULL) && | 1104 if ((constant != NULL) && |
1105 constant->value().IsInstance() && | 1105 constant->value().IsInstance() && |
1106 Instance::Cast(constant->value()).IsClosure()) { | 1106 Instance::Cast(constant->value()).IsClosure()) { |
1107 target ^= Closure::function(Instance::Cast(constant->value())); | 1107 target ^= Closure::function(Instance::Cast(constant->value())); |
1108 } | 1108 } |
1109 | 1109 |
1110 if (target.IsNull()) { | 1110 if (target.IsNull()) { |
1111 TRACE_INLINING(ISL_Print(" Bailout: non-closure operator\n")); | 1111 TRACE_INLINING(THR_Print(" Bailout: non-closure operator\n")); |
1112 continue; | 1112 continue; |
1113 } | 1113 } |
1114 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1114 GrowableArray<Value*> arguments(call->ArgumentCount()); |
1115 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1115 for (int i = 0; i < call->ArgumentCount(); ++i) { |
1116 arguments.Add(call->PushArgumentAt(i)->value()); | 1116 arguments.Add(call->PushArgumentAt(i)->value()); |
1117 } | 1117 } |
1118 InlinedCallData call_data( | 1118 InlinedCallData call_data( |
1119 call, &arguments, call_info[call_idx].caller(), | 1119 call, &arguments, call_info[call_idx].caller(), |
1120 call_info[call_idx].caller_graph->inlining_id()); | 1120 call_info[call_idx].caller_graph->inlining_id()); |
1121 if (TryInlining(target, | 1121 if (TryInlining(target, |
1122 call->argument_names(), | 1122 call->argument_names(), |
1123 &call_data)) { | 1123 &call_data)) { |
1124 InlineCall(&call_data); | 1124 InlineCall(&call_data); |
1125 } | 1125 } |
1126 } | 1126 } |
1127 } | 1127 } |
1128 | 1128 |
1129 void InlineInstanceCalls() { | 1129 void InlineInstanceCalls() { |
1130 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1130 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
1131 inlining_call_sites_->instance_calls(); | 1131 inlining_call_sites_->instance_calls(); |
1132 TRACE_INLINING(ISL_Print(" Polymorphic Instance Calls (%" Pd ")\n", | 1132 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", |
1133 call_info.length())); | 1133 call_info.length())); |
1134 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1134 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
1135 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1135 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
1136 if (call->with_checks()) { | 1136 if (call->with_checks()) { |
1137 // PolymorphicInliner introduces deoptimization paths. | 1137 // PolymorphicInliner introduces deoptimization paths. |
1138 if (!FLAG_polymorphic_with_deopt) return; | 1138 if (!FLAG_polymorphic_with_deopt) return; |
1139 const Function& cl = call_info[call_idx].caller(); | 1139 const Function& cl = call_info[call_idx].caller(); |
1140 intptr_t caller_inlining_id = | 1140 intptr_t caller_inlining_id = |
1141 call_info[call_idx].caller_graph->inlining_id(); | 1141 call_info[call_idx].caller_graph->inlining_id(); |
1142 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1142 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
1143 inliner.Inline(); | 1143 inliner.Inline(); |
1144 continue; | 1144 continue; |
1145 } | 1145 } |
1146 | 1146 |
1147 const ICData& ic_data = call->ic_data(); | 1147 const ICData& ic_data = call->ic_data(); |
1148 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 1148 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
1149 if (!inliner_->AlwaysInline(target) && | 1149 if (!inliner_->AlwaysInline(target) && |
1150 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1150 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
1151 TRACE_INLINING(ISL_Print( | 1151 TRACE_INLINING(THR_Print( |
1152 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1152 " => %s (deopt count %d)\n Bailout: cold %f\n", |
1153 target.ToCString(), | 1153 target.ToCString(), |
1154 target.deoptimization_counter(), | 1154 target.deoptimization_counter(), |
1155 call_info[call_idx].ratio)); | 1155 call_info[call_idx].ratio)); |
1156 PRINT_INLINING_TREE("Too cold", | 1156 PRINT_INLINING_TREE("Too cold", |
1157 &call_info[call_idx].caller(), &target, call); | 1157 &call_info[call_idx].caller(), &target, call); |
1158 continue; | 1158 continue; |
1159 } | 1159 } |
1160 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1160 GrowableArray<Value*> arguments(call->ArgumentCount()); |
1161 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { | 1161 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
(...skipping 660 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1822 (function.name() == Symbols::AssignIndexToken().raw()) || | 1822 (function.name() == Symbols::AssignIndexToken().raw()) || |
1823 (function.name() == Symbols::Plus().raw()) || | 1823 (function.name() == Symbols::Plus().raw()) || |
1824 (function.name() == Symbols::Minus().raw()); | 1824 (function.name() == Symbols::Minus().raw()); |
1825 } | 1825 } |
1826 | 1826 |
1827 | 1827 |
1828 bool FlowGraphInliner::AlwaysInline(const Function& function) { | 1828 bool FlowGraphInliner::AlwaysInline(const Function& function) { |
1829 const char* kAlwaysInlineAnnotation = "AlwaysInline"; | 1829 const char* kAlwaysInlineAnnotation = "AlwaysInline"; |
1830 if (FLAG_enable_inlining_annotations && | 1830 if (FLAG_enable_inlining_annotations && |
1831 HasAnnotation(function, kAlwaysInlineAnnotation)) { | 1831 HasAnnotation(function, kAlwaysInlineAnnotation)) { |
1832 TRACE_INLINING(ISL_Print("AlwaysInline annotation for %s\n", | 1832 TRACE_INLINING(THR_Print("AlwaysInline annotation for %s\n", |
1833 function.ToCString())); | 1833 function.ToCString())); |
1834 return true; | 1834 return true; |
1835 } | 1835 } |
1836 | 1836 |
1837 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || | 1837 if (function.IsImplicitGetterFunction() || function.IsGetterFunction() || |
1838 function.IsImplicitSetterFunction() || function.IsSetterFunction() || | 1838 function.IsImplicitSetterFunction() || function.IsSetterFunction() || |
1839 IsInlineableOperator(function)) { | 1839 IsInlineableOperator(function)) { |
1840 const intptr_t count = function.optimized_instruction_count(); | 1840 const intptr_t count = function.optimized_instruction_count(); |
1841 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { | 1841 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
1842 return true; | 1842 return true; |
1843 } | 1843 } |
1844 } | 1844 } |
1845 return MethodRecognizer::AlwaysInline(function); | 1845 return MethodRecognizer::AlwaysInline(function); |
1846 } | 1846 } |
1847 | 1847 |
1848 | 1848 |
1849 void FlowGraphInliner::Inline() { | 1849 void FlowGraphInliner::Inline() { |
1850 // Collect graph info and store it on the function. | 1850 // Collect graph info and store it on the function. |
1851 // We might later use it for an early bailout from the inlining. | 1851 // We might later use it for an early bailout from the inlining. |
1852 CollectGraphInfo(flow_graph_); | 1852 CollectGraphInfo(flow_graph_); |
1853 | 1853 |
1854 const Function& top = flow_graph_->function(); | 1854 const Function& top = flow_graph_->function(); |
1855 if ((FLAG_inlining_filter != NULL) && | 1855 if ((FLAG_inlining_filter != NULL) && |
1856 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 1856 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
1857 return; | 1857 return; |
1858 } | 1858 } |
1859 | 1859 |
1860 TRACE_INLINING(ISL_Print("Inlining calls in %s\n", top.ToCString())); | 1860 TRACE_INLINING(THR_Print("Inlining calls in %s\n", top.ToCString())); |
1861 | 1861 |
1862 if (trace_inlining() && | 1862 if (trace_inlining() && |
1863 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 1863 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
1864 ISL_Print("Before Inlining of %s\n", flow_graph_-> | 1864 THR_Print("Before Inlining of %s\n", flow_graph_-> |
1865 function().ToFullyQualifiedCString()); | 1865 function().ToFullyQualifiedCString()); |
1866 FlowGraphPrinter printer(*flow_graph_); | 1866 FlowGraphPrinter printer(*flow_graph_); |
1867 printer.PrintBlocks(); | 1867 printer.PrintBlocks(); |
1868 } | 1868 } |
1869 | 1869 |
1870 CallSiteInliner inliner(this); | 1870 CallSiteInliner inliner(this); |
1871 inliner.InlineCalls(); | 1871 inliner.InlineCalls(); |
1872 if (FLAG_print_inlining_tree) { | 1872 if (FLAG_print_inlining_tree) { |
1873 inliner.PrintInlinedInfo(top); | 1873 inliner.PrintInlinedInfo(top); |
1874 } | 1874 } |
1875 | 1875 |
1876 if (inliner.inlined()) { | 1876 if (inliner.inlined()) { |
1877 flow_graph_->DiscoverBlocks(); | 1877 flow_graph_->DiscoverBlocks(); |
1878 if (trace_inlining()) { | 1878 if (trace_inlining()) { |
1879 ISL_Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 1879 THR_Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
1880 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 1880 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
1881 ISL_Print("After Inlining of %s\n", flow_graph_-> | 1881 THR_Print("After Inlining of %s\n", flow_graph_-> |
1882 function().ToFullyQualifiedCString()); | 1882 function().ToFullyQualifiedCString()); |
1883 FlowGraphPrinter printer(*flow_graph_); | 1883 FlowGraphPrinter printer(*flow_graph_); |
1884 printer.PrintBlocks(); | 1884 printer.PrintBlocks(); |
1885 } | 1885 } |
1886 } | 1886 } |
1887 } | 1887 } |
1888 } | 1888 } |
1889 | 1889 |
1890 | 1890 |
1891 intptr_t FlowGraphInliner::NextInlineId(const Function& function, | 1891 intptr_t FlowGraphInliner::NextInlineId(const Function& function, |
1892 intptr_t parent_id) { | 1892 intptr_t parent_id) { |
1893 const intptr_t id = inline_id_to_function_->length(); | 1893 const intptr_t id = inline_id_to_function_->length(); |
1894 inline_id_to_function_->Add(&function); | 1894 inline_id_to_function_->Add(&function); |
1895 caller_inline_id_->Add(parent_id); | 1895 caller_inline_id_->Add(parent_id); |
1896 return id; | 1896 return id; |
1897 } | 1897 } |
1898 | 1898 |
1899 | 1899 |
1900 } // namespace dart | 1900 } // namespace dart |
OLD | NEW |