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 659 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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(THR_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 = thread()->deopt_id(); |
681 isolate()->set_deopt_id(0); | 681 thread()->set_deopt_id(0); |
682 // Install bailout jump. | 682 // Install bailout jump. |
683 LongJumpScope jump; | 683 LongJumpScope jump; |
684 if (setjmp(*jump.Set()) == 0) { | 684 if (setjmp(*jump.Set()) == 0) { |
685 // Parse the callee function. | 685 // Parse the callee function. |
686 bool in_cache; | 686 bool in_cache; |
687 ParsedFunction* parsed_function; | 687 ParsedFunction* parsed_function; |
688 { | 688 { |
689 CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer); | 689 CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer); |
690 parsed_function = GetParsedFunction(function, &in_cache); | 690 parsed_function = GetParsedFunction(function, &in_cache); |
691 } | 691 } |
692 | 692 |
693 // Load IC data for the callee. | 693 // Load IC data for the callee. |
694 ZoneGrowableArray<const ICData*>* ic_data_array = | 694 ZoneGrowableArray<const ICData*>* ic_data_array = |
695 new(Z) ZoneGrowableArray<const ICData*>(); | 695 new(Z) ZoneGrowableArray<const ICData*>(); |
696 function.RestoreICDataMap(ic_data_array); | 696 function.RestoreICDataMap(ic_data_array); |
697 | 697 |
698 // Build the callee graph. | 698 // Build the callee graph. |
699 InlineExitCollector* exit_collector = | 699 InlineExitCollector* exit_collector = |
700 new(Z) InlineExitCollector(caller_graph_, call); | 700 new(Z) InlineExitCollector(caller_graph_, call); |
701 FlowGraphBuilder builder(*parsed_function, | 701 FlowGraphBuilder builder(*parsed_function, |
702 *ic_data_array, | 702 *ic_data_array, |
703 exit_collector, | 703 exit_collector, |
704 Isolate::kNoDeoptId); | 704 Thread::kNoDeoptId); |
705 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 705 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
706 FlowGraph* callee_graph; | 706 FlowGraph* callee_graph; |
707 { | 707 { |
708 CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer); | 708 CSTAT_TIMER_SCOPE(thread(), graphinliner_build_timer); |
709 callee_graph = builder.BuildGraph(); | 709 callee_graph = builder.BuildGraph(); |
710 } | 710 } |
711 | 711 |
712 // The parameter stubs are a copy of the actual arguments providing | 712 // The parameter stubs are a copy of the actual arguments providing |
713 // concrete information about the values, for example constant values, | 713 // concrete information about the values, for example constant values, |
714 // without linking between the caller and callee graphs. | 714 // without linking between the caller and callee graphs. |
(...skipping 91 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
806 | 806 |
807 // Use heuristics do decide if this call should be inlined. | 807 // Use heuristics do decide if this call should be inlined. |
808 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { | 808 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { |
809 // If size is larger than all thresholds, don't consider it again. | 809 // If size is larger than all thresholds, don't consider it again. |
810 if ((size > FLAG_inlining_size_threshold) && | 810 if ((size > FLAG_inlining_size_threshold) && |
811 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 811 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
812 (size > FLAG_inlining_constant_arguments_min_size_threshold) && | 812 (size > FLAG_inlining_constant_arguments_min_size_threshold) && |
813 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { | 813 (size > FLAG_inlining_constant_arguments_max_size_threshold)) { |
814 function.set_is_inlinable(false); | 814 function.set_is_inlinable(false); |
815 } | 815 } |
816 isolate()->set_deopt_id(prev_deopt_id); | 816 thread()->set_deopt_id(prev_deopt_id); |
817 TRACE_INLINING(THR_Print(" Bailout: heuristics with " | 817 TRACE_INLINING(THR_Print(" Bailout: heuristics with " |
818 "code size: %" Pd ", " | 818 "code size: %" Pd ", " |
819 "call sites: %" Pd ", " | 819 "call sites: %" Pd ", " |
820 "const args: %" Pd "\n", | 820 "const args: %" Pd "\n", |
821 size, | 821 size, |
822 call_site_count, | 822 call_site_count, |
823 constants_count)); | 823 constants_count)); |
824 PRINT_INLINING_TREE("Heuristic fail", | 824 PRINT_INLINING_TREE("Heuristic fail", |
825 &call_data->caller, &function, call_data->call); | 825 &call_data->caller, &function, call_data->call); |
826 return false; | 826 return false; |
827 } | 827 } |
828 | 828 |
829 // Inline dispatcher methods regardless of the current depth. | 829 // Inline dispatcher methods regardless of the current depth. |
830 const intptr_t depth = | 830 const intptr_t depth = |
831 (function.IsInvokeFieldDispatcher() || | 831 (function.IsInvokeFieldDispatcher() || |
832 function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_; | 832 function.IsNoSuchMethodDispatcher()) ? 0 : inlining_depth_; |
833 collected_call_sites_->FindCallSites(callee_graph, depth, &inlined_info_); | 833 collected_call_sites_->FindCallSites(callee_graph, depth, &inlined_info_); |
834 | 834 |
835 // Add the function to the cache. | 835 // Add the function to the cache. |
836 if (!in_cache) { | 836 if (!in_cache) { |
837 function_cache_.Add(parsed_function); | 837 function_cache_.Add(parsed_function); |
838 } | 838 } |
839 | 839 |
840 // Build succeeded so we restore the bailout jump. | 840 // Build succeeded so we restore the bailout jump. |
841 inlined_ = true; | 841 inlined_ = true; |
842 inlined_size_ += size; | 842 inlined_size_ += size; |
843 if (is_recursive_call) { | 843 if (is_recursive_call) { |
844 inlined_recursive_call_ = true; | 844 inlined_recursive_call_ = true; |
845 } | 845 } |
846 isolate()->set_deopt_id(prev_deopt_id); | 846 thread()->set_deopt_id(prev_deopt_id); |
847 | 847 |
848 call_data->callee_graph = callee_graph; | 848 call_data->callee_graph = callee_graph; |
849 call_data->parameter_stubs = param_stubs; | 849 call_data->parameter_stubs = param_stubs; |
850 call_data->exit_collector = exit_collector; | 850 call_data->exit_collector = exit_collector; |
851 | 851 |
852 // When inlined, we add the guarded fields of the callee to the caller's | 852 // When inlined, we add the guarded fields of the callee to the caller's |
853 // list of guarded fields. | 853 // list of guarded fields. |
854 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { | 854 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { |
855 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), | 855 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), |
856 (*callee_graph->guarded_fields())[i]); | 856 (*callee_graph->guarded_fields())[i]); |
857 } | 857 } |
858 // When inlined, we add the deferred prefixes of the callee to the | 858 // When inlined, we add the deferred prefixes of the callee to the |
859 // caller's list of deferred prefixes. | 859 // caller's list of deferred prefixes. |
860 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); | 860 caller_graph()->AddToDeferredPrefixes(callee_graph->deferred_prefixes()); |
861 | 861 |
862 FlowGraphInliner::SetInliningId(callee_graph, | 862 FlowGraphInliner::SetInliningId(callee_graph, |
863 inliner_->NextInlineId(callee_graph->function(), | 863 inliner_->NextInlineId(callee_graph->function(), |
864 call_data->caller_inlining_id_)); | 864 call_data->caller_inlining_id_)); |
865 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 865 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
866 // disconnected from its function during the rest of compilation. | 866 // disconnected from its function during the rest of compilation. |
867 Code::ZoneHandle(unoptimized_code.raw()); | 867 Code::ZoneHandle(unoptimized_code.raw()); |
868 TRACE_INLINING(THR_Print(" Success\n")); | 868 TRACE_INLINING(THR_Print(" Success\n")); |
869 PRINT_INLINING_TREE(NULL, | 869 PRINT_INLINING_TREE(NULL, |
870 &call_data->caller, &function, call); | 870 &call_data->caller, &function, call); |
871 return true; | 871 return true; |
872 } else { | 872 } else { |
873 Error& error = Error::Handle(); | 873 Error& error = Error::Handle(); |
874 error = isolate()->object_store()->sticky_error(); | 874 error = isolate()->object_store()->sticky_error(); |
875 isolate()->object_store()->clear_sticky_error(); | 875 isolate()->object_store()->clear_sticky_error(); |
876 isolate()->set_deopt_id(prev_deopt_id); | 876 thread()->set_deopt_id(prev_deopt_id); |
877 TRACE_INLINING(THR_Print(" Bailout: %s\n", error.ToErrorCString())); | 877 TRACE_INLINING(THR_Print(" Bailout: %s\n", error.ToErrorCString())); |
878 PRINT_INLINING_TREE("Bailout", | 878 PRINT_INLINING_TREE("Bailout", |
879 &call_data->caller, &function, call); | 879 &call_data->caller, &function, call); |
880 return false; | 880 return false; |
881 } | 881 } |
882 } | 882 } |
883 | 883 |
884 void PrintInlinedInfo(const Function& top) { | 884 void PrintInlinedInfo(const Function& top) { |
885 if (inlined_info_.length() > 0) { | 885 if (inlined_info_.length() > 0) { |
886 THR_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", | 886 THR_Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", |
(...skipping 603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1490 result, | 1490 result, |
1491 call_->env(), // Return can become deoptimization target. | 1491 call_->env(), // Return can become deoptimization target. |
1492 FlowGraph::kEffect); | 1492 FlowGraph::kEffect); |
1493 entry->set_last_instruction(result); | 1493 entry->set_last_instruction(result); |
1494 exit_collector->AddExit(result); | 1494 exit_collector->AddExit(result); |
1495 ParsedFunction* temp_parsed_function = | 1495 ParsedFunction* temp_parsed_function = |
1496 new ParsedFunction(Thread::Current(), target); | 1496 new ParsedFunction(Thread::Current(), target); |
1497 GraphEntryInstr* graph_entry = | 1497 GraphEntryInstr* graph_entry = |
1498 new(Z) GraphEntryInstr(*temp_parsed_function, | 1498 new(Z) GraphEntryInstr(*temp_parsed_function, |
1499 entry, | 1499 entry, |
1500 Isolate::kNoDeoptId); // No OSR id. | 1500 Thread::kNoDeoptId); // No OSR id. |
1501 // Update polymorphic inliner state. | 1501 // Update polymorphic inliner state. |
1502 inlined_entries_.Add(graph_entry); | 1502 inlined_entries_.Add(graph_entry); |
1503 exit_collector_->Union(exit_collector); | 1503 exit_collector_->Union(exit_collector); |
1504 return true; | 1504 return true; |
1505 } | 1505 } |
1506 return false; | 1506 return false; |
1507 } | 1507 } |
1508 | 1508 |
1509 | 1509 |
1510 // Build a DAG to dispatch to the inlined function bodies. Load the class | 1510 // Build a DAG to dispatch to the inlined function bodies. Load the class |
(...skipping 373 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1884 intptr_t FlowGraphInliner::NextInlineId(const Function& function, | 1884 intptr_t FlowGraphInliner::NextInlineId(const Function& function, |
1885 intptr_t parent_id) { | 1885 intptr_t parent_id) { |
1886 const intptr_t id = inline_id_to_function_->length(); | 1886 const intptr_t id = inline_id_to_function_->length(); |
1887 inline_id_to_function_->Add(&function); | 1887 inline_id_to_function_->Add(&function); |
1888 caller_inline_id_->Add(parent_id); | 1888 caller_inline_id_->Add(parent_id); |
1889 return id; | 1889 return id; |
1890 } | 1890 } |
1891 | 1891 |
1892 | 1892 |
1893 } // namespace dart | 1893 } // namespace dart |
OLD | NEW |