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

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

Issue 10952002: Reapply "Deoptimization support in inlined code." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/flow_graph_compiler.cc ('k') | runtime/vm/il_printer.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) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, 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/compiler.h"
7 #include "vm/flags.h" 8 #include "vm/flags.h"
8 #include "vm/flow_graph.h" 9 #include "vm/flow_graph.h"
9 #include "vm/flow_graph_builder.h" 10 #include "vm/flow_graph_builder.h"
11 #include "vm/flow_graph_optimizer.h"
10 #include "vm/il_printer.h" 12 #include "vm/il_printer.h"
13 #include "vm/intrinsifier.h"
11 #include "vm/longjump.h" 14 #include "vm/longjump.h"
12 #include "vm/object.h" 15 #include "vm/object.h"
13 #include "vm/object_store.h" 16 #include "vm/object_store.h"
14 17
15 namespace dart { 18 namespace dart {
16 19
17 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); 20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
18 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); 21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
19 DECLARE_FLAG(bool, print_flow_graph); 22 DECLARE_FLAG(bool, print_flow_graph);
23 DECLARE_FLAG(int, deoptimization_counter_threshold);
20 24
21 #define TRACE_INLINING(statement) \ 25 #define TRACE_INLINING(statement) \
22 do { \ 26 do { \
23 if (FLAG_trace_inlining) statement; \ 27 if (FLAG_trace_inlining) statement; \
24 } while (false) 28 } while (false)
25 29
26 30
27 class CallSiteInliner : public FlowGraphVisitor { 31 class CallSiteInliner : public FlowGraphVisitor {
28 public: 32 public:
29 explicit CallSiteInliner(FlowGraph* flow_graph) 33 explicit CallSiteInliner(FlowGraph* flow_graph)
30 : FlowGraphVisitor(flow_graph->postorder()), 34 : FlowGraphVisitor(flow_graph->postorder()),
31 caller_graph_(flow_graph), 35 caller_graph_(flow_graph),
32 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), 36 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
33 inlined_(false) { } 37 inlined_(false) { }
34 38
35 bool TryInlining(const Function& function, 39 bool TryInlining(const Function& function,
36 GrowableArray<Value*>* arguments, 40 GrowableArray<Value*>* arguments,
37 Definition* call) { 41 Definition* call) {
38 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); 42 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString()));
39 43
40 // Abort if the callee has optional parameters. 44 // Abort if the callee has optional parameters.
41 if (function.HasOptionalParameters()) { 45 if (function.HasOptionalParameters()) {
42 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n")); 46 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n"));
43 return false; 47 return false;
44 } 48 }
45 49
46 // Assuming no optional parameters the actual/formal count should match. 50 // Assuming no optional parameters the actual/formal count should match.
47 ASSERT(arguments->length() == function.num_fixed_parameters()); 51 ASSERT(arguments->length() == function.num_fixed_parameters());
48 52
53 // Abort if the callee has an intrinsic translation.
54 if (Intrinsifier::CanIntrinsify(function)) {
55 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n"));
56 return false;
57 }
58
49 Isolate* isolate = Isolate::Current(); 59 Isolate* isolate = Isolate::Current();
50 // Save and clear IC data. 60 // Save and clear IC data.
51 const Array& old_ic_data = Array::Handle(isolate->ic_data_array()); 61 const Array& prev_ic_data = Array::Handle(isolate->ic_data_array());
52 isolate->set_ic_data_array(Array::null()); 62 isolate->set_ic_data_array(Array::null());
63 // Save and clear deopt id.
64 const intptr_t prev_deopt_id = isolate->deopt_id();
65 isolate->set_deopt_id(0);
53 // Install bailout jump. 66 // Install bailout jump.
54 LongJump* base = isolate->long_jump_base(); 67 LongJump* base = isolate->long_jump_base();
55 LongJump jump; 68 LongJump jump;
56 isolate->set_long_jump_base(&jump); 69 isolate->set_long_jump_base(&jump);
57 if (setjmp(*jump.Set()) == 0) { 70 if (setjmp(*jump.Set()) == 0) {
58 // Parse the callee function. 71 // Parse the callee function.
59 ParsedFunction parsed_function(function); 72 ParsedFunction parsed_function(function);
60 Parser::ParseFunction(&parsed_function); 73 Parser::ParseFunction(&parsed_function);
61 parsed_function.AllocateVariables(); 74 parsed_function.AllocateVariables();
62 FlowGraphBuilder builder(parsed_function); 75
76 // Load IC data for the callee.
77 if ((function.deoptimization_counter() <
78 FLAG_deoptimization_counter_threshold) &&
79 function.HasCode()) {
80 const Code& unoptimized_code =
81 Code::Handle(function.unoptimized_code());
82 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
83 }
63 84
64 // Build the callee graph. 85 // Build the callee graph.
86 FlowGraphBuilder builder(parsed_function);
65 FlowGraph* callee_graph = 87 FlowGraph* callee_graph =
66 builder.BuildGraph(FlowGraphBuilder::kValueContext); 88 builder.BuildGraph(FlowGraphBuilder::kValueContext);
67 89
68 // Abort if the callee graph contains control flow. 90 // Abort if the callee graph contains control flow.
69 if (callee_graph->preorder().length() != 2) { 91 if (callee_graph->preorder().length() != 2) {
70 isolate->set_long_jump_base(base); 92 isolate->set_long_jump_base(base);
71 isolate->set_ic_data_array(old_ic_data.raw()); 93 isolate->set_ic_data_array(prev_ic_data.raw());
72 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); 94 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
73 return false; 95 return false;
74 } 96 }
75 97
98 // Compute SSA on the callee graph, catching bailouts.
99 callee_graph->ComputeSSA(next_ssa_temp_index_);
100 callee_graph->ComputeUseLists();
101
102 // TODO(zerny): Do more optimization passes on the callee graph.
103 FlowGraphOptimizer optimizer(callee_graph);
104 optimizer.ApplyICData();
105 callee_graph->ComputeUseLists();
106
76 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 107 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
77 OS::Print("Callee graph before SSA %s\n", 108 OS::Print("Callee graph for inlining %s\n",
78 parsed_function.function().ToFullyQualifiedCString()); 109 parsed_function.function().ToFullyQualifiedCString());
79 FlowGraphPrinter printer(*callee_graph); 110 FlowGraphPrinter printer(*callee_graph);
80 printer.PrintBlocks(); 111 printer.PrintBlocks();
81 } 112 }
82 113
83 // Compute SSA on the callee graph. (catching bailouts)
84 callee_graph->ComputeSSA(next_ssa_temp_index_);
85
86 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
87 OS::Print("Callee graph after SSA %s\n",
88 parsed_function.function().ToFullyQualifiedCString());
89 FlowGraphPrinter printer(*callee_graph);
90 printer.PrintBlocks();
91 }
92
93 callee_graph->ComputeUseLists();
94
95 // TODO(zerny): Do optimization passes on the callee graph.
96
97 // TODO(zerny): If result is more than size threshold then abort. 114 // TODO(zerny): If result is more than size threshold then abort.
98 115
99 // TODO(zerny): If effort is less than threshold then inline recursively. 116 // TODO(zerny): If effort is less than threshold then inline recursively.
100 117
101 // Plug result in the caller graph. 118 // Plug result in the caller graph.
102 caller_graph_->InlineCall(call, callee_graph); 119 caller_graph_->InlineCall(call, callee_graph);
103 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 120 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
104 121
105 // Remove (all) push arguments of the call. 122 // Check that inlining maintains use lists.
123 DEBUG_ASSERT(caller_graph_->ValidateUseLists());
124
125 // Remove push arguments of the call.
106 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 126 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
107 PushArgumentInstr* push = call->ArgumentAt(i); 127 PushArgumentInstr* push = call->ArgumentAt(i);
108 push->ReplaceUsesWith(push->value()->definition()); 128 push->ReplaceUsesWith(push->value()->definition());
109 push->RemoveFromGraph(); 129 push->RemoveFromGraph();
110 } 130 }
111 131
112 // Replace all the formal parameters with the actuals. 132 // Replace formal parameters with actuals.
113 for (intptr_t i = 0; i < arguments->length(); ++i) { 133 for (intptr_t i = 0; i < arguments->length(); ++i) {
114 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i); 134 Value* val = callee_graph->graph_entry()->start_env()->ValueAt(i);
115 ParameterInstr* param = val->definition()->AsParameter(); 135 ParameterInstr* param = val->definition()->AsParameter();
116 ASSERT(param != NULL); 136 ASSERT(param != NULL);
117 param->ReplaceUsesWith((*arguments)[i]->definition()); 137 param->ReplaceUsesWith((*arguments)[i]->definition());
118 } 138 }
119 139
120 // Replace callee's null constant with caller's null constant. 140 // Replace callee's null constant with caller's null constant.
121 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( 141 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
122 caller_graph_->graph_entry()->constant_null()); 142 caller_graph_->graph_entry()->constant_null());
123 143
124 TRACE_INLINING(OS::Print(" Success\n")); 144 TRACE_INLINING(OS::Print(" Success\n"));
125 145
126 // Build succeeded so we restore the bailout jump. 146 // Build succeeded so we restore the bailout jump.
127 inlined_ = true; 147 inlined_ = true;
128 isolate->set_long_jump_base(base); 148 isolate->set_long_jump_base(base);
129 isolate->set_ic_data_array(old_ic_data.raw()); 149 isolate->set_deopt_id(prev_deopt_id);
150 isolate->set_ic_data_array(prev_ic_data.raw());
130 return true; 151 return true;
131 } else { 152 } else {
132 Error& error = Error::Handle(); 153 Error& error = Error::Handle();
133 error = isolate->object_store()->sticky_error(); 154 error = isolate->object_store()->sticky_error();
134 isolate->object_store()->clear_sticky_error(); 155 isolate->object_store()->clear_sticky_error();
135 isolate->set_long_jump_base(base); 156 isolate->set_long_jump_base(base);
136 isolate->set_ic_data_array(old_ic_data.raw()); 157 isolate->set_deopt_id(prev_deopt_id);
158 isolate->set_ic_data_array(prev_ic_data.raw());
137 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 159 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
138 return false; 160 return false;
139 } 161 }
140 } 162 }
141 163
142 void VisitClosureCall(ClosureCallInstr* call) { 164 void VisitClosureCall(ClosureCallInstr* call) {
143 TRACE_INLINING(OS::Print(" ClosureCall\n")); 165 TRACE_INLINING(OS::Print(" ClosureCall\n"));
144 // Find the closure of the callee. 166 // Find the closure of the callee.
145 ASSERT(call->ArgumentCount() > 0); 167 ASSERT(call->ArgumentCount() > 0);
146 const CreateClosureInstr* closure = 168 const CreateClosureInstr* closure =
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
192 214
193 215
194 void FlowGraphInliner::Inline() { 216 void FlowGraphInliner::Inline() {
195 if ((FLAG_inlining_filter != NULL) && 217 if ((FLAG_inlining_filter != NULL) &&
196 (strstr(flow_graph_-> 218 (strstr(flow_graph_->
197 parsed_function().function().ToFullyQualifiedCString(), 219 parsed_function().function().ToFullyQualifiedCString(),
198 FLAG_inlining_filter) == NULL)) { 220 FLAG_inlining_filter) == NULL)) {
199 return; 221 return;
200 } 222 }
201 223
224 TRACE_INLINING(OS::Print(
225 "Inlining calls in %s\n",
226 flow_graph_->parsed_function().function().ToCString()));
227
202 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 228 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
203 OS::Print("Before Inlining of %s\n", flow_graph_-> 229 OS::Print("Before Inlining of %s\n", flow_graph_->
204 parsed_function().function().ToFullyQualifiedCString()); 230 parsed_function().function().ToFullyQualifiedCString());
205 FlowGraphPrinter printer(*flow_graph_); 231 FlowGraphPrinter printer(*flow_graph_);
206 printer.PrintBlocks(); 232 printer.PrintBlocks();
207 } 233 }
208 234
209 TRACE_INLINING(OS::Print(
210 "Inlining calls in %s\n",
211 flow_graph_->parsed_function().function().ToCString()));
212 CallSiteInliner inliner(flow_graph_); 235 CallSiteInliner inliner(flow_graph_);
213 inliner.VisitBlocks(); 236 inliner.VisitBlocks();
214 237
215 if (inliner.inlined()) { 238 if (inliner.inlined()) {
216 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 239 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
217 OS::Print("After Inlining of %s\n", flow_graph_-> 240 OS::Print("After Inlining of %s\n", flow_graph_->
218 parsed_function().function().ToFullyQualifiedCString()); 241 parsed_function().function().ToFullyQualifiedCString());
219 FlowGraphPrinter printer(*flow_graph_); 242 FlowGraphPrinter printer(*flow_graph_);
220 printer.PrintBlocks(); 243 printer.PrintBlocks();
221 } 244 }
222 } 245 }
223 } 246 }
224 247
225 } // namespace dart 248 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_compiler.cc ('k') | runtime/vm/il_printer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698