| 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 |