| OLD | NEW |
| 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/compiler.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/flow_graph.h" | 9 #include "vm/flow_graph.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| 11 #include "vm/flow_graph_optimizer.h" | 11 #include "vm/flow_graph_optimizer.h" |
| 12 #include "vm/il_printer.h" | 12 #include "vm/il_printer.h" |
| 13 #include "vm/intrinsifier.h" | 13 #include "vm/intrinsifier.h" |
| 14 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
| 15 #include "vm/object.h" | 15 #include "vm/object.h" |
| 16 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 17 | 17 |
| 18 namespace dart { | 18 namespace dart { |
| 19 | 19 |
| 20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); | 20 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
| 21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); | 21 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
| 22 DEFINE_FLAG(int, inlining_size_threshold, 250, | |
| 23 "Inline only functions with up to threshold instructions"); | |
| 24 DEFINE_FLAG(int, inlining_growth_factor, 3, | |
| 25 "Stop inlining when a function grows by the factor"); | |
| 26 DECLARE_FLAG(bool, print_flow_graph); | 22 DECLARE_FLAG(bool, print_flow_graph); |
| 27 DECLARE_FLAG(int, deoptimization_counter_threshold); | 23 DECLARE_FLAG(int, deoptimization_counter_threshold); |
| 28 | 24 |
| 29 #define TRACE_INLINING(statement) \ | 25 #define TRACE_INLINING(statement) \ |
| 30 do { \ | 26 do { \ |
| 31 if (FLAG_trace_inlining) statement; \ | 27 if (FLAG_trace_inlining) statement; \ |
| 32 } while (false) | 28 } while (false) |
| 33 | 29 |
| 34 | 30 |
| 35 // Test if a call is recursive by looking in the deoptimization environment. | 31 // Test if a call is recursive by looking in the deoptimization environment. |
| 36 static bool IsCallRecursive(const Function& function, Definition* call) { | 32 static bool IsCallRecursive(const Function& function, Definition* call) { |
| 37 Environment* env = call->env(); | 33 Environment* env = call->env(); |
| 38 while (env != NULL) { | 34 while (env != NULL) { |
| 39 if (function.raw() == env->function().raw()) return true; | 35 if (function.raw() == env->function().raw()) return true; |
| 40 env = env->outer(); | 36 env = env->outer(); |
| 41 } | 37 } |
| 42 return false; | 38 return false; |
| 43 } | 39 } |
| 44 | 40 |
| 45 | 41 |
| 46 class CallSiteInliner : public FlowGraphVisitor { | 42 class CallSiteInliner : public FlowGraphVisitor { |
| 47 public: | 43 public: |
| 48 explicit CallSiteInliner(FlowGraph* flow_graph) | 44 explicit CallSiteInliner(FlowGraph* flow_graph) |
| 49 : FlowGraphVisitor(flow_graph->postorder()), | 45 : FlowGraphVisitor(flow_graph->postorder()), |
| 50 caller_graph_(flow_graph), | 46 caller_graph_(flow_graph), |
| 51 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), | 47 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), |
| 52 inlined_(false), | 48 inlined_(false) { } |
| 53 initial_size_(flow_graph->InstructionCount()), | |
| 54 inlined_size_(0), | |
| 55 static_calls_(), | |
| 56 closure_calls_(), | |
| 57 instance_calls_() { } | |
| 58 | 49 |
| 59 void VisitClosureCall(ClosureCallInstr* call) { | |
| 60 closure_calls_.Add(call); | |
| 61 } | |
| 62 | |
| 63 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { | |
| 64 instance_calls_.Add(call); | |
| 65 } | |
| 66 | |
| 67 void VisitStaticCall(StaticCallInstr* call) { | |
| 68 if (call->function().is_inlinable()) static_calls_.Add(call); | |
| 69 } | |
| 70 | |
| 71 void FindCallSites() { | |
| 72 VisitBlocks(); | |
| 73 } | |
| 74 | |
| 75 void InlineCalls() { | |
| 76 InlineStaticCalls(); | |
| 77 InlineClosureCalls(); | |
| 78 InlineInstanceCalls(); | |
| 79 } | |
| 80 | |
| 81 bool inlined() const { return inlined_; } | |
| 82 | |
| 83 double GrowthFactor() const { | |
| 84 return static_cast<double>(inlined_size_) / | |
| 85 static_cast<double>(initial_size_); | |
| 86 } | |
| 87 | |
| 88 private: | |
| 89 bool TryInlining(const Function& function, | 50 bool TryInlining(const Function& function, |
| 90 GrowableArray<Value*>* arguments, | 51 GrowableArray<Value*>* arguments, |
| 91 Definition* call) { | 52 Definition* call) { |
| 92 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); | 53 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); |
| 93 | 54 |
| 94 // Abort if the inlinable bit on the function is low. | 55 // Abort if the inlinable bit on the function is low. |
| 95 if (!function.is_inlinable()) { | 56 if (!function.is_inlinable()) { |
| 96 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); | 57 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); |
| 97 return false; | 58 return false; |
| 98 } | 59 } |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 if ((function.deoptimization_counter() < | 102 if ((function.deoptimization_counter() < |
| 142 FLAG_deoptimization_counter_threshold) && | 103 FLAG_deoptimization_counter_threshold) && |
| 143 function.HasCode()) { | 104 function.HasCode()) { |
| 144 const Code& unoptimized_code = | 105 const Code& unoptimized_code = |
| 145 Code::Handle(function.unoptimized_code()); | 106 Code::Handle(function.unoptimized_code()); |
| 146 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); | 107 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); |
| 147 } | 108 } |
| 148 | 109 |
| 149 // Build the callee graph. | 110 // Build the callee graph. |
| 150 FlowGraphBuilder builder(parsed_function); | 111 FlowGraphBuilder builder(parsed_function); |
| 151 builder.SetInitialBlockId(caller_graph_->max_block_id()); | |
| 152 FlowGraph* callee_graph = | 112 FlowGraph* callee_graph = |
| 153 builder.BuildGraph(FlowGraphBuilder::kValueContext); | 113 builder.BuildGraph(FlowGraphBuilder::kValueContext); |
| 154 | 114 |
| 115 // Abort if the callee graph contains control flow. |
| 116 if (callee_graph->preorder().length() != 2) { |
| 117 function.set_is_inlinable(false); |
| 118 isolate->set_long_jump_base(base); |
| 119 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 120 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); |
| 121 return false; |
| 122 } |
| 123 |
| 155 // Compute SSA on the callee graph, catching bailouts. | 124 // Compute SSA on the callee graph, catching bailouts. |
| 156 callee_graph->ComputeSSA(next_ssa_temp_index_); | 125 callee_graph->ComputeSSA(next_ssa_temp_index_); |
| 157 callee_graph->ComputeUseLists(); | 126 callee_graph->ComputeUseLists(); |
| 158 | 127 |
| 159 // TODO(zerny): Do more optimization passes on the callee graph. | 128 // TODO(zerny): Do more optimization passes on the callee graph. |
| 160 FlowGraphOptimizer optimizer(callee_graph); | 129 FlowGraphOptimizer optimizer(callee_graph); |
| 161 optimizer.ApplyICData(); | 130 optimizer.ApplyICData(); |
| 162 callee_graph->ComputeUseLists(); | 131 callee_graph->ComputeUseLists(); |
| 163 | 132 |
| 164 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 133 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 165 OS::Print("Callee graph for inlining %s\n", | 134 OS::Print("Callee graph for inlining %s\n", |
| 166 parsed_function.function().ToFullyQualifiedCString()); | 135 parsed_function.function().ToFullyQualifiedCString()); |
| 167 FlowGraphPrinter printer(*callee_graph); | 136 FlowGraphPrinter printer(*callee_graph); |
| 168 printer.PrintBlocks(); | 137 printer.PrintBlocks(); |
| 169 } | 138 } |
| 170 | 139 |
| 171 // If result is more than size threshold then abort. | 140 // TODO(zerny): If result is more than size threshold then abort. |
| 172 // TODO(zerny): Do this after CP and dead code elimination. | |
| 173 intptr_t size = callee_graph->InstructionCount(); | |
| 174 if (size > FLAG_inlining_size_threshold) { | |
| 175 function.set_is_inlinable(false); | |
| 176 isolate->set_long_jump_base(base); | |
| 177 isolate->set_deopt_id(prev_deopt_id); | |
| 178 isolate->set_ic_data_array(prev_ic_data.raw()); | |
| 179 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size)); | |
| 180 return false; | |
| 181 } | |
| 182 | |
| 183 // If the growth factor is more than threshold abort. | |
| 184 double growth = | |
| 185 static_cast<double>(inlined_size_ + size) / | |
| 186 static_cast<double>(initial_size_); | |
| 187 if (growth > static_cast<double>(FLAG_inlining_growth_factor)) { | |
| 188 function.set_is_inlinable(false); | |
| 189 isolate->set_long_jump_base(base); | |
| 190 isolate->set_deopt_id(prev_deopt_id); | |
| 191 isolate->set_ic_data_array(prev_ic_data.raw()); | |
| 192 TRACE_INLINING(OS::Print(" Bailout: growth factor %f\n", | |
| 193 growth)); | |
| 194 return false; | |
| 195 } | |
| 196 | 141 |
| 197 // TODO(zerny): If effort is less than threshold then inline recursively. | 142 // TODO(zerny): If effort is less than threshold then inline recursively. |
| 198 | 143 |
| 199 // Plug result in the caller graph. | 144 // Plug result in the caller graph. |
| 200 caller_graph_->InlineCall(call, callee_graph); | 145 caller_graph_->InlineCall(call, callee_graph); |
| 201 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); | 146 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); |
| 202 | 147 |
| 148 // Check that inlining maintains use lists. |
| 149 DEBUG_ASSERT(caller_graph_->ValidateUseLists()); |
| 150 |
| 203 // Remove push arguments of the call. | 151 // Remove push arguments of the call. |
| 204 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 152 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 205 PushArgumentInstr* push = call->ArgumentAt(i); | 153 PushArgumentInstr* push = call->ArgumentAt(i); |
| 206 push->ReplaceUsesWith(push->value()->definition()); | 154 push->ReplaceUsesWith(push->value()->definition()); |
| 207 push->RemoveFromGraph(); | 155 push->RemoveFromGraph(); |
| 208 } | 156 } |
| 209 | 157 |
| 210 // Replace formal parameters with actuals. | 158 // Replace formal parameters with actuals. |
| 211 intptr_t arg_index = 0; | 159 intptr_t arg_index = 0; |
| 212 GrowableArray<Definition*>* defns = | 160 GrowableArray<Definition*>* defns = |
| 213 callee_graph->graph_entry()->initial_definitions(); | 161 callee_graph->graph_entry()->initial_definitions(); |
| 214 for (intptr_t i = 0; i < defns->length(); ++i) { | 162 for (intptr_t i = 0; i < defns->length(); ++i) { |
| 215 ParameterInstr* param = (*defns)[i]->AsParameter(); | 163 ParameterInstr* param = (*defns)[i]->AsParameter(); |
| 216 if (param != NULL) { | 164 if (param != NULL) { |
| 217 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); | 165 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); |
| 218 } | 166 } |
| 219 } | 167 } |
| 220 ASSERT(arg_index == arguments->length()); | 168 ASSERT(arg_index == arguments->length()); |
| 221 | 169 |
| 222 // Replace callee's null constant with caller's null constant. | 170 // Replace callee's null constant with caller's null constant. |
| 223 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( | 171 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith( |
| 224 caller_graph_->graph_entry()->constant_null()); | 172 caller_graph_->graph_entry()->constant_null()); |
| 225 | 173 |
| 226 TRACE_INLINING(OS::Print(" Success\n")); | 174 TRACE_INLINING(OS::Print(" Success\n")); |
| 227 | 175 |
| 228 // Check that inlining maintains use lists. | |
| 229 DEBUG_ASSERT(caller_graph_->ValidateUseLists()); | |
| 230 | |
| 231 // Build succeeded so we restore the bailout jump. | 176 // Build succeeded so we restore the bailout jump. |
| 232 inlined_ = true; | 177 inlined_ = true; |
| 233 inlined_size_ += size; | |
| 234 isolate->set_long_jump_base(base); | 178 isolate->set_long_jump_base(base); |
| 235 isolate->set_deopt_id(prev_deopt_id); | 179 isolate->set_deopt_id(prev_deopt_id); |
| 236 isolate->set_ic_data_array(prev_ic_data.raw()); | 180 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 237 return true; | 181 return true; |
| 238 } else { | 182 } else { |
| 239 Error& error = Error::Handle(); | 183 Error& error = Error::Handle(); |
| 240 error = isolate->object_store()->sticky_error(); | 184 error = isolate->object_store()->sticky_error(); |
| 241 isolate->object_store()->clear_sticky_error(); | 185 isolate->object_store()->clear_sticky_error(); |
| 242 isolate->set_long_jump_base(base); | 186 isolate->set_long_jump_base(base); |
| 243 isolate->set_deopt_id(prev_deopt_id); | 187 isolate->set_deopt_id(prev_deopt_id); |
| 244 isolate->set_ic_data_array(prev_ic_data.raw()); | 188 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 245 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 189 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 246 return false; | 190 return false; |
| 247 } | 191 } |
| 248 } | 192 } |
| 249 | 193 |
| 250 void InlineStaticCalls() { | 194 void VisitClosureCall(ClosureCallInstr* call) { |
| 251 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", | 195 TRACE_INLINING(OS::Print(" ClosureCall\n")); |
| 252 static_calls_.length())); | 196 // Find the closure of the callee. |
| 253 for (intptr_t i = 0; i < static_calls_.length(); ++i) { | 197 ASSERT(call->ArgumentCount() > 0); |
| 254 StaticCallInstr* call = static_calls_[i]; | 198 const CreateClosureInstr* closure = |
| 255 GrowableArray<Value*> arguments(call->ArgumentCount()); | 199 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); |
| 256 for (int i = 0; i < call->ArgumentCount(); ++i) { | 200 if (closure == NULL) { |
| 257 arguments.Add(call->ArgumentAt(i)->value()); | 201 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); |
| 258 } | 202 return; |
| 259 TryInlining(call->function(), &arguments, call); | |
| 260 } | 203 } |
| 204 GrowableArray<Value*> arguments(call->ArgumentCount() - 1); |
| 205 for (int i = 1; i < call->ArgumentCount(); ++i) { |
| 206 arguments.Add(call->ArgumentAt(i)->value()); |
| 207 } |
| 208 TryInlining(closure->function(), &arguments, call); |
| 261 } | 209 } |
| 262 | 210 |
| 263 void InlineClosureCalls() { | 211 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* instr) { |
| 264 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", | 212 TRACE_INLINING(OS::Print(" PolymorphicInstanceCall\n")); |
| 265 closure_calls_.length())); | 213 const ICData& ic_data = instr->ic_data(); |
| 266 for (intptr_t i = 0; i < closure_calls_.length(); ++i) { | 214 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 267 ClosureCallInstr* call = closure_calls_[i]; | 215 if (instr->with_checks()) { |
| 268 // Find the closure of the callee. | 216 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n", |
| 269 ASSERT(call->ArgumentCount() > 0); | 217 ic_data.NumberOfChecks(), |
| 270 const CreateClosureInstr* closure = | 218 target.ToCString())); |
| 271 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); | 219 return; |
| 272 if (closure == NULL) { | |
| 273 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); | |
| 274 continue; | |
| 275 } | |
| 276 GrowableArray<Value*> arguments(call->ArgumentCount() - 1); | |
| 277 for (int i = 1; i < call->ArgumentCount(); ++i) { | |
| 278 arguments.Add(call->ArgumentAt(i)->value()); | |
| 279 } | |
| 280 TryInlining(closure->function(), &arguments, call); | |
| 281 } | 220 } |
| 221 |
| 222 GrowableArray<Value*> arguments(instr->ArgumentCount()); |
| 223 for (int i = 0; i < instr->ArgumentCount(); ++i) { |
| 224 arguments.Add(instr->ArgumentAt(i)->value()); |
| 225 } |
| 226 |
| 227 TryInlining(target, &arguments, instr); |
| 282 } | 228 } |
| 283 | 229 |
| 284 void InlineInstanceCalls() { | 230 void VisitStaticCall(StaticCallInstr* call) { |
| 285 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", | 231 TRACE_INLINING(OS::Print(" StaticCall\n")); |
| 286 instance_calls_.length())); | 232 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 287 for (intptr_t i = 0; i < instance_calls_.length(); ++i) { | 233 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 288 PolymorphicInstanceCallInstr* instr = instance_calls_[i]; | 234 arguments.Add(call->ArgumentAt(i)->value()); |
| 289 const ICData& ic_data = instr->ic_data(); | |
| 290 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | |
| 291 if (instr->with_checks()) { | |
| 292 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n", | |
| 293 ic_data.NumberOfChecks(), | |
| 294 target.ToCString())); | |
| 295 continue; | |
| 296 } | |
| 297 GrowableArray<Value*> arguments(instr->ArgumentCount()); | |
| 298 for (int i = 0; i < instr->ArgumentCount(); ++i) { | |
| 299 arguments.Add(instr->ArgumentAt(i)->value()); | |
| 300 } | |
| 301 TryInlining(target, &arguments, instr); | |
| 302 } | 235 } |
| 236 TryInlining(call->function(), &arguments, call); |
| 303 } | 237 } |
| 304 | 238 |
| 239 bool inlined() const { return inlined_; } |
| 240 |
| 241 private: |
| 305 FlowGraph* caller_graph_; | 242 FlowGraph* caller_graph_; |
| 306 intptr_t next_ssa_temp_index_; | 243 intptr_t next_ssa_temp_index_; |
| 307 bool inlined_; | 244 bool inlined_; |
| 308 intptr_t initial_size_; | |
| 309 intptr_t inlined_size_; | |
| 310 | |
| 311 GrowableArray<StaticCallInstr*> static_calls_; | |
| 312 GrowableArray<ClosureCallInstr*> closure_calls_; | |
| 313 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_; | |
| 314 }; | 245 }; |
| 315 | 246 |
| 316 | 247 |
| 317 void FlowGraphInliner::Inline() { | 248 void FlowGraphInliner::Inline() { |
| 318 if ((FLAG_inlining_filter != NULL) && | 249 if ((FLAG_inlining_filter != NULL) && |
| 319 (strstr(flow_graph_-> | 250 (strstr(flow_graph_-> |
| 320 parsed_function().function().ToFullyQualifiedCString(), | 251 parsed_function().function().ToFullyQualifiedCString(), |
| 321 FLAG_inlining_filter) == NULL)) { | 252 FLAG_inlining_filter) == NULL)) { |
| 322 return; | 253 return; |
| 323 } | 254 } |
| 324 | 255 |
| 325 TRACE_INLINING(OS::Print( | 256 TRACE_INLINING(OS::Print( |
| 326 "Inlining calls in %s\n", | 257 "Inlining calls in %s\n", |
| 327 flow_graph_->parsed_function().function().ToCString())); | 258 flow_graph_->parsed_function().function().ToCString())); |
| 328 | 259 |
| 329 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 260 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 330 OS::Print("Before Inlining of %s\n", flow_graph_-> | 261 OS::Print("Before Inlining of %s\n", flow_graph_-> |
| 331 parsed_function().function().ToFullyQualifiedCString()); | 262 parsed_function().function().ToFullyQualifiedCString()); |
| 332 FlowGraphPrinter printer(*flow_graph_); | 263 FlowGraphPrinter printer(*flow_graph_); |
| 333 printer.PrintBlocks(); | 264 printer.PrintBlocks(); |
| 334 } | 265 } |
| 335 | 266 |
| 336 CallSiteInliner inliner(flow_graph_); | 267 CallSiteInliner inliner(flow_graph_); |
| 337 inliner.FindCallSites(); | 268 inliner.VisitBlocks(); |
| 338 inliner.InlineCalls(); | |
| 339 | 269 |
| 340 if (inliner.inlined()) { | 270 if (inliner.inlined()) { |
| 341 if (FLAG_trace_inlining) { | 271 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 342 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 272 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 343 if (FLAG_print_flow_graph) { | 273 parsed_function().function().ToFullyQualifiedCString()); |
| 344 OS::Print("After Inlining of %s\n", flow_graph_-> | 274 FlowGraphPrinter printer(*flow_graph_); |
| 345 parsed_function().function().ToFullyQualifiedCString()); | 275 printer.PrintBlocks(); |
| 346 FlowGraphPrinter printer(*flow_graph_); | |
| 347 printer.PrintBlocks(); | |
| 348 } | |
| 349 } | 276 } |
| 350 } | 277 } |
| 351 } | 278 } |
| 352 | 279 |
| 353 } // namespace dart | 280 } // namespace dart |
| OLD | NEW |