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

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

Issue 11029027: Recursive inlining. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 8 years, 2 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 | « no previous file | no next file » | 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/assert.h" 7 #include "vm/assert.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"
11 #include "vm/flow_graph_builder.h" 11 #include "vm/flow_graph_builder.h"
12 #include "vm/flow_graph_optimizer.h" 12 #include "vm/flow_graph_optimizer.h"
13 #include "vm/il_printer.h" 13 #include "vm/il_printer.h"
14 #include "vm/intrinsifier.h" 14 #include "vm/intrinsifier.h"
15 #include "vm/longjump.h" 15 #include "vm/longjump.h"
16 #include "vm/object.h" 16 #include "vm/object.h"
17 #include "vm/object_store.h" 17 #include "vm/object_store.h"
18 18
19 namespace dart { 19 namespace dart {
20 20
21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); 21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining");
22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); 22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function");
23 DEFINE_FLAG(int, inlining_size_threshold, 250, 23 DEFINE_FLAG(int, inlining_size_threshold, 250,
24 "Inline only functions with up to threshold instructions"); 24 "Inline only functions with up to threshold instructions (default 250)");
25 DEFINE_FLAG(int, inlining_depth_threshold, 0,
26 "Inline recursively up to threshold depth (default 0, ie, disabled)");
25 DEFINE_FLAG(bool, inline_control_flow, true, 27 DEFINE_FLAG(bool, inline_control_flow, true,
26 "Inline functions with control flow."); 28 "Inline functions with control flow.");
27 DECLARE_FLAG(bool, print_flow_graph); 29 DECLARE_FLAG(bool, print_flow_graph);
28 DECLARE_FLAG(int, deoptimization_counter_threshold); 30 DECLARE_FLAG(int, deoptimization_counter_threshold);
29 31
30 #define TRACE_INLINING(statement) \ 32 #define TRACE_INLINING(statement) \
31 do { \ 33 do { \
32 if (FLAG_trace_inlining) statement; \ 34 if (FLAG_trace_inlining) statement; \
33 } while (false) 35 } while (false)
34 36
35 37
36 // Test if a call is recursive by looking in the deoptimization environment. 38 // Test if a call is recursive by looking in the deoptimization environment.
37 static bool IsCallRecursive(const Function& function, Definition* call) { 39 static bool IsCallRecursive(const Function& function, Definition* call) {
38 Environment* env = call->env(); 40 Environment* env = call->env();
39 while (env != NULL) { 41 while (env != NULL) {
40 if (function.raw() == env->function().raw()) return true; 42 if (function.raw() == env->function().raw()) return true;
41 env = env->outer(); 43 env = env->outer();
42 } 44 }
43 return false; 45 return false;
44 } 46 }
45 47
46 48
47 class CallSiteInliner : public FlowGraphVisitor { 49 // A collection of call sites.
50 class CallSites : public FlowGraphVisitor {
48 public: 51 public:
49 explicit CallSiteInliner(FlowGraph* flow_graph) 52 explicit CallSites(FlowGraph* flow_graph)
50 : FlowGraphVisitor(flow_graph->postorder()), 53 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
51 caller_graph_(flow_graph),
52 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
53 inlined_(false),
54 initial_size_(flow_graph->InstructionCount()),
55 inlined_size_(0),
56 static_calls_(), 54 static_calls_(),
57 closure_calls_(), 55 closure_calls_(),
58 instance_calls_() { } 56 instance_calls_() { }
59 57
58 GrowableArray<StaticCallInstr*>* static_calls() {
59 return &static_calls_;
60 }
61
62 GrowableArray<ClosureCallInstr*>* closure_calls() {
63 return &closure_calls_;
64 }
65
66 GrowableArray<PolymorphicInstanceCallInstr*>* instance_calls() {
67 return &instance_calls_;
68 }
69
70 bool HasCalls() const {
71 return !(static_calls_.is_empty() &&
72 closure_calls_.is_empty() &&
73 instance_calls_.is_empty());
74 }
75
76 void Clear() {
77 static_calls_.Clear();
78 closure_calls_.Clear();
79 instance_calls_.Clear();
80 }
81
82 void FindCallSites(FlowGraph* graph) {
83 BlockIterator block_it = graph->postorder_iterator();
84 for (; !block_it.Done(); block_it.Advance()) {
85 ForwardInstructionIterator it(block_it.Current());
86 for (; !it.Done(); it.Advance()) {
87 it.Current()->Accept(this);
88 }
89 }
90 }
91
60 void VisitClosureCall(ClosureCallInstr* call) { 92 void VisitClosureCall(ClosureCallInstr* call) {
61 closure_calls_.Add(call); 93 closure_calls_.Add(call);
62 } 94 }
63 95
64 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) { 96 void VisitPolymorphicInstanceCall(PolymorphicInstanceCallInstr* call) {
65 instance_calls_.Add(call); 97 instance_calls_.Add(call);
66 } 98 }
67 99
68 void VisitStaticCall(StaticCallInstr* call) { 100 void VisitStaticCall(StaticCallInstr* call) {
69 if (call->function().is_inlinable()) static_calls_.Add(call); 101 if (call->function().is_inlinable()) static_calls_.Add(call);
70 } 102 }
srdjan 2012/10/04 17:06:26 Why not adding VisitInstanceCall as well? Then we
zerny-google 2012/10/08 11:44:28 The collection of call sites happens after we have
srdjan 2012/10/08 15:31:03 Please add something similar to the comment of the
71 103
72 void FindCallSites() { 104 private:
73 VisitBlocks(); 105 GrowableArray<StaticCallInstr*> static_calls_;
74 } 106 GrowableArray<ClosureCallInstr*> closure_calls_;
107 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
108
109 DISALLOW_COPY_AND_ASSIGN(CallSites);
110 };
111
112
113 class CallSiteInliner : public ValueObject {
114 public:
115 explicit CallSiteInliner(FlowGraph* flow_graph)
116 : caller_graph_(flow_graph),
117 next_ssa_temp_index_(flow_graph->max_virtual_register_number()),
118 inlined_(false),
119 initial_size_(flow_graph->InstructionCount()),
120 inlined_size_(0),
121 inlining_depth_(1),
122 collected_call_sites_(NULL),
123 inlining_call_sites_(NULL) { }
75 124
76 void InlineCalls() { 125 void InlineCalls() {
77 InlineStaticCalls(); 126 // Create two call site collections to swap between.
78 InlineClosureCalls(); 127 CallSites sites1(caller_graph_);
79 InlineInstanceCalls(); 128 CallSites sites2(caller_graph_);
129 CallSites* call_sites_temp = NULL;
130 collected_call_sites_ = &sites1;
131 inlining_call_sites_ = &sites2;
132 // Collect initial call sites.
133 collected_call_sites_->FindCallSites(caller_graph_);
134 while (collected_call_sites_->HasCalls()) {
135 TRACE_INLINING(OS::Print(" Depth %"Pd" ----------\n",
136 inlining_depth_ - 1));
137 // Swap collected and inlining arrays and clear the new collecting array.
138 call_sites_temp = collected_call_sites_;
139 collected_call_sites_ = inlining_call_sites_;
140 inlining_call_sites_ = call_sites_temp;
141 collected_call_sites_->Clear();
142 // Inline call sites at the current depth.
143 InlineStaticCalls();
144 InlineClosureCalls();
145 InlineInstanceCalls();
146 // Increment the inlining depth. Checked before recursive inlining.
147 ++inlining_depth_;
148 }
srdjan 2012/10/04 17:06:26 Reset collected_call_sites_ and inlining_call_site
zerny-google 2012/10/08 11:44:28 Done.
80 } 149 }
81 150
82 bool inlined() const { return inlined_; } 151 bool inlined() const { return inlined_; }
83 152
84 double GrowthFactor() const { 153 double GrowthFactor() const {
85 return static_cast<double>(inlined_size_) / 154 return static_cast<double>(inlined_size_) /
86 static_cast<double>(initial_size_); 155 static_cast<double>(initial_size_);
87 } 156 }
88 157
89 private: 158 private:
90 bool TryInlining(const Function& function, 159 bool TryInlining(const Function& function,
91 GrowableArray<Value*>* arguments, 160 GrowableArray<Value*>* arguments,
92 Definition* call) { 161 Definition* call) {
93 TRACE_INLINING(OS::Print(" => %s\n", function.ToCString())); 162 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n",
163 function.ToCString(),
164 function.deoptimization_counter()));
94 165
95 // Abort if the inlinable bit on the function is low. 166 // Abort if the inlinable bit on the function is low.
96 if (!function.is_inlinable()) { 167 if (!function.is_inlinable()) {
97 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 168 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
98 return false; 169 return false;
99 } 170 }
100 171
101 // Abort if the callee has optional parameters. 172 // Abort if the callee has optional parameters.
102 if (function.HasOptionalParameters()) { 173 if (function.HasOptionalParameters()) {
103 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n")); 174 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n"));
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); 224 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray());
154 } 225 }
155 226
156 // Build the callee graph. 227 // Build the callee graph.
157 FlowGraphBuilder builder(parsed_function); 228 FlowGraphBuilder builder(parsed_function);
158 builder.SetInitialBlockId(caller_graph_->max_block_id()); 229 builder.SetInitialBlockId(caller_graph_->max_block_id());
159 FlowGraph* callee_graph = 230 FlowGraph* callee_graph =
160 builder.BuildGraph(FlowGraphBuilder::kValueContext); 231 builder.BuildGraph(FlowGraphBuilder::kValueContext);
161 232
162 // Abort if the callee graph contains control flow. 233 // Abort if the callee graph contains control flow.
163 if ((callee_graph->preorder().length() != 2) && 234 if (!FLAG_inline_control_flow &&
164 !FLAG_inline_control_flow) { 235 (callee_graph->preorder().length() != 2)) {
165 function.set_is_inlinable(false); 236 function.set_is_inlinable(false);
166 isolate->set_long_jump_base(base); 237 isolate->set_long_jump_base(base);
167 isolate->set_ic_data_array(prev_ic_data.raw()); 238 isolate->set_ic_data_array(prev_ic_data.raw());
168 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); 239 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
169 return false; 240 return false;
170 } 241 }
171 242
172 // Compute SSA on the callee graph, catching bailouts. 243 // Compute SSA on the callee graph, catching bailouts.
173 callee_graph->ComputeSSA(next_ssa_temp_index_); 244 callee_graph->ComputeSSA(next_ssa_temp_index_);
174 callee_graph->ComputeUseLists(); 245 callee_graph->ComputeUseLists();
(...skipping 15 matching lines...) Expand all
190 intptr_t size = callee_graph->InstructionCount(); 261 intptr_t size = callee_graph->InstructionCount();
191 if (size > FLAG_inlining_size_threshold) { 262 if (size > FLAG_inlining_size_threshold) {
192 function.set_is_inlinable(false); 263 function.set_is_inlinable(false);
193 isolate->set_long_jump_base(base); 264 isolate->set_long_jump_base(base);
194 isolate->set_deopt_id(prev_deopt_id); 265 isolate->set_deopt_id(prev_deopt_id);
195 isolate->set_ic_data_array(prev_ic_data.raw()); 266 isolate->set_ic_data_array(prev_ic_data.raw());
196 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size)); 267 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size));
197 return false; 268 return false;
198 } 269 }
199 270
200 // TODO(zerny): If effort is less than threshold then inline recursively. 271 // If depth is less or equal to threshold recursively add call sites.
272 if (inlining_depth_ <= FLAG_inlining_depth_threshold) {
srdjan 2012/10/04 17:06:26 The inlining depth threshold is not keeping inlini
zerny-google 2012/10/08 11:44:28 Implicitly it is. The flag is an upper bound on th
srdjan 2012/10/08 15:31:03 I am looking at it from the point of user running
273 collected_call_sites_->FindCallSites(callee_graph);
274 }
201 275
202 // Plug result in the caller graph. 276 // Plug result in the caller graph.
203 caller_graph_->InlineCall(call, callee_graph); 277 caller_graph_->InlineCall(call, callee_graph);
204 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 278 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
205 279
206 // Remove push arguments of the call. 280 // Remove push arguments of the call.
207 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 281 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
208 PushArgumentInstr* push = call->ArgumentAt(i); 282 PushArgumentInstr* push = call->ArgumentAt(i);
209 push->ReplaceUsesWith(push->value()->definition()); 283 push->ReplaceUsesWith(push->value()->definition());
210 push->RemoveFromGraph(); 284 push->RemoveFromGraph();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 isolate->object_store()->clear_sticky_error(); 318 isolate->object_store()->clear_sticky_error();
245 isolate->set_long_jump_base(base); 319 isolate->set_long_jump_base(base);
246 isolate->set_deopt_id(prev_deopt_id); 320 isolate->set_deopt_id(prev_deopt_id);
247 isolate->set_ic_data_array(prev_ic_data.raw()); 321 isolate->set_ic_data_array(prev_ic_data.raw());
248 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 322 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
249 return false; 323 return false;
250 } 324 }
251 } 325 }
252 326
253 void InlineStaticCalls() { 327 void InlineStaticCalls() {
254 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", 328 const GrowableArray<StaticCallInstr*>& calls =
255 static_calls_.length())); 329 *inlining_call_sites_->static_calls();
256 for (intptr_t i = 0; i < static_calls_.length(); ++i) { 330 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length()));
257 StaticCallInstr* call = static_calls_[i]; 331 for (intptr_t i = 0; i < calls.length(); ++i) {
332 StaticCallInstr* call = calls[i];
258 GrowableArray<Value*> arguments(call->ArgumentCount()); 333 GrowableArray<Value*> arguments(call->ArgumentCount());
259 for (int i = 0; i < call->ArgumentCount(); ++i) { 334 for (int i = 0; i < call->ArgumentCount(); ++i) {
260 arguments.Add(call->ArgumentAt(i)->value()); 335 arguments.Add(call->ArgumentAt(i)->value());
261 } 336 }
262 TryInlining(call->function(), &arguments, call); 337 TryInlining(call->function(), &arguments, call);
263 } 338 }
264 } 339 }
265 340
266 void InlineClosureCalls() { 341 void InlineClosureCalls() {
267 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", 342 const GrowableArray<ClosureCallInstr*>& calls =
268 closure_calls_.length())); 343 *inlining_call_sites_->closure_calls();
269 for (intptr_t i = 0; i < closure_calls_.length(); ++i) { 344 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length()));
270 ClosureCallInstr* call = closure_calls_[i]; 345 for (intptr_t i = 0; i < calls.length(); ++i) {
346 ClosureCallInstr* call = calls[i];
271 // Find the closure of the callee. 347 // Find the closure of the callee.
272 ASSERT(call->ArgumentCount() > 0); 348 ASSERT(call->ArgumentCount() > 0);
273 const CreateClosureInstr* closure = 349 const CreateClosureInstr* closure =
274 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 350 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
275 if (closure == NULL) { 351 if (closure == NULL) {
276 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 352 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
277 continue; 353 continue;
278 } 354 }
279 GrowableArray<Value*> arguments(call->ArgumentCount() - 1); 355 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
280 for (int i = 1; i < call->ArgumentCount(); ++i) { 356 for (int i = 1; i < call->ArgumentCount(); ++i) {
281 arguments.Add(call->ArgumentAt(i)->value()); 357 arguments.Add(call->ArgumentAt(i)->value());
282 } 358 }
283 TryInlining(closure->function(), &arguments, call); 359 TryInlining(closure->function(), &arguments, call);
284 } 360 }
285 } 361 }
286 362
287 void InlineInstanceCalls() { 363 void InlineInstanceCalls() {
364 const GrowableArray<PolymorphicInstanceCallInstr*>& calls =
365 *inlining_call_sites_->instance_calls();
288 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", 366 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
289 instance_calls_.length())); 367 calls.length()));
290 for (intptr_t i = 0; i < instance_calls_.length(); ++i) { 368 for (intptr_t i = 0; i < calls.length(); ++i) {
291 PolymorphicInstanceCallInstr* instr = instance_calls_[i]; 369 PolymorphicInstanceCallInstr* instr = calls[i];
292 const ICData& ic_data = instr->ic_data(); 370 const ICData& ic_data = instr->ic_data();
293 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 371 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
294 if (instr->with_checks()) { 372 if (instr->with_checks()) {
295 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n", 373 TRACE_INLINING(OS::Print(" Bailout: %"Pd" checks target '%s'\n",
296 ic_data.NumberOfChecks(), 374 ic_data.NumberOfChecks(),
297 target.ToCString())); 375 target.ToCString()));
298 continue; 376 continue;
299 } 377 }
300 GrowableArray<Value*> arguments(instr->ArgumentCount()); 378 GrowableArray<Value*> arguments(instr->ArgumentCount());
301 for (int i = 0; i < instr->ArgumentCount(); ++i) { 379 for (int i = 0; i < instr->ArgumentCount(); ++i) {
302 arguments.Add(instr->ArgumentAt(i)->value()); 380 arguments.Add(instr->ArgumentAt(i)->value());
303 } 381 }
304 TryInlining(target, &arguments, instr); 382 TryInlining(target, &arguments, instr);
305 } 383 }
306 } 384 }
307 385
308 FlowGraph* caller_graph_; 386 FlowGraph* caller_graph_;
309 intptr_t next_ssa_temp_index_; 387 intptr_t next_ssa_temp_index_;
310 bool inlined_; 388 bool inlined_;
311 intptr_t initial_size_; 389 intptr_t initial_size_;
312 intptr_t inlined_size_; 390 intptr_t inlined_size_;
391 intptr_t inlining_depth_;
392 CallSites* collected_call_sites_;
393 CallSites* inlining_call_sites_;
313 394
314 GrowableArray<StaticCallInstr*> static_calls_; 395 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner);
315 GrowableArray<ClosureCallInstr*> closure_calls_;
316 GrowableArray<PolymorphicInstanceCallInstr*> instance_calls_;
317 }; 396 };
318 397
319 398
320 void FlowGraphInliner::Inline() { 399 void FlowGraphInliner::Inline() {
321 if ((FLAG_inlining_filter != NULL) && 400 if ((FLAG_inlining_filter != NULL) &&
322 (strstr(flow_graph_-> 401 (strstr(flow_graph_->
323 parsed_function().function().ToFullyQualifiedCString(), 402 parsed_function().function().ToFullyQualifiedCString(),
324 FLAG_inlining_filter) == NULL)) { 403 FLAG_inlining_filter) == NULL)) {
325 return; 404 return;
326 } 405 }
327 406
328 TRACE_INLINING(OS::Print( 407 TRACE_INLINING(OS::Print(
329 "Inlining calls in %s\n", 408 "Inlining calls in %s\n",
330 flow_graph_->parsed_function().function().ToCString())); 409 flow_graph_->parsed_function().function().ToCString()));
331 410
332 if (FLAG_trace_inlining && FLAG_print_flow_graph) { 411 if (FLAG_trace_inlining && FLAG_print_flow_graph) {
333 OS::Print("Before Inlining of %s\n", flow_graph_-> 412 OS::Print("Before Inlining of %s\n", flow_graph_->
334 parsed_function().function().ToFullyQualifiedCString()); 413 parsed_function().function().ToFullyQualifiedCString());
335 FlowGraphPrinter printer(*flow_graph_); 414 FlowGraphPrinter printer(*flow_graph_);
336 printer.PrintBlocks(); 415 printer.PrintBlocks();
337 } 416 }
338 417
339 CallSiteInliner inliner(flow_graph_); 418 CallSiteInliner inliner(flow_graph_);
340 inliner.FindCallSites();
341 inliner.InlineCalls(); 419 inliner.InlineCalls();
342 420
343 if (inliner.inlined()) { 421 if (inliner.inlined()) {
344 if (FLAG_trace_inlining) { 422 if (FLAG_trace_inlining) {
345 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); 423 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor());
346 if (FLAG_print_flow_graph) { 424 if (FLAG_print_flow_graph) {
347 OS::Print("After Inlining of %s\n", flow_graph_-> 425 OS::Print("After Inlining of %s\n", flow_graph_->
348 parsed_function().function().ToFullyQualifiedCString()); 426 parsed_function().function().ToFullyQualifiedCString());
349 FlowGraphPrinter printer(*flow_graph_); 427 FlowGraphPrinter printer(*flow_graph_);
350 printer.PrintBlocks(); 428 printer.PrintBlocks();
351 } 429 }
352 } 430 }
353 } 431 }
354 } 432 }
355 433
356 } // namespace dart 434 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698