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

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

Issue 11028140: Inlining of calls with optional parameters. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Update 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 | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.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/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"
(...skipping 13 matching lines...) Expand all
24 "Inline only functions with up to threshold instructions (default 50)"); 24 "Inline only functions with up to threshold instructions (default 50)");
25 // TODO(srdjan): set to 3 once crash in apidoc.dart is resolved. 25 // TODO(srdjan): set to 3 once crash in apidoc.dart is resolved.
26 DEFINE_FLAG(int, inlining_depth_threshold, 3, 26 DEFINE_FLAG(int, inlining_depth_threshold, 3,
27 "Inline recursively up to threshold depth (default 3)"); 27 "Inline recursively up to threshold depth (default 3)");
28 DEFINE_FLAG(bool, inline_control_flow, true, 28 DEFINE_FLAG(bool, inline_control_flow, true,
29 "Inline functions with control flow."); 29 "Inline functions with control flow.");
30 DECLARE_FLAG(bool, print_flow_graph); 30 DECLARE_FLAG(bool, print_flow_graph);
31 DECLARE_FLAG(int, deoptimization_counter_threshold); 31 DECLARE_FLAG(int, deoptimization_counter_threshold);
32 DECLARE_FLAG(bool, verify_compiler); 32 DECLARE_FLAG(bool, verify_compiler);
33 DECLARE_FLAG(bool, compiler_stats); 33 DECLARE_FLAG(bool, compiler_stats);
34 DECLARE_FLAG(bool, reject_named_argument_as_positional);
srdjan 2012/10/23 16:00:52 Remove?
srdjan 2012/10/23 16:02:37 Actually not yet :-)... sorry
34 35
35 #define TRACE_INLINING(statement) \ 36 #define TRACE_INLINING(statement) \
36 do { \ 37 do { \
37 if (FLAG_trace_inlining) statement; \ 38 if (FLAG_trace_inlining) statement; \
38 } while (false) 39 } while (false)
39 40
40 41
41 // Test if a call is recursive by looking in the deoptimization environment. 42 // Test if a call is recursive by looking in the deoptimization environment.
42 static bool IsCallRecursive(const Function& function, Definition* call) { 43 static bool IsCallRecursive(const Function& function, Definition* call) {
43 Environment* env = call->env(); 44 Environment* env = call->env();
44 while (env != NULL) { 45 while (env != NULL) {
45 if (function.raw() == env->function().raw()) return true; 46 if (function.raw() == env->function().raw()) return true;
46 env = env->outer(); 47 env = env->outer();
47 } 48 }
48 return false; 49 return false;
49 } 50 }
50 51
51 52
52 // TODO(zerny): Remove the following classes once we have moved the label/join 53 // TODO(zerny): Remove the ChildrenVisitor and SourceLabelResetter once we have
53 // map for control flow out of the AST an into the flow graph builder. 54 // moved the label/join map for control flow out of the AST an into the flow
55 // graph builder.
54 56
55 // Default visitor to traverse child nodes. 57 // Default visitor to traverse child nodes.
56 class ChildrenVisitor : public AstNodeVisitor { 58 class ChildrenVisitor : public AstNodeVisitor {
57 public: 59 public:
58 ChildrenVisitor() { } 60 ChildrenVisitor() { }
59 #define DEFINE_VISIT(type, name) \ 61 #define DEFINE_VISIT(type, name) \
60 virtual void Visit##type(type* node) { node->VisitChildren(this); } 62 virtual void Visit##type(type* node) { node->VisitChildren(this); }
61 NODE_LIST(DEFINE_VISIT); 63 NODE_LIST(DEFINE_VISIT);
62 #undef DEFINE_VISIT 64 #undef DEFINE_VISIT
63 }; 65 };
(...skipping 26 matching lines...) Expand all
90 } 92 }
91 void Reset(AstNode* node, SourceLabel* lbl) { 93 void Reset(AstNode* node, SourceLabel* lbl) {
92 node->VisitChildren(this); 94 node->VisitChildren(this);
93 if (lbl == NULL) return; 95 if (lbl == NULL) return;
94 lbl->join_for_break_ = NULL; 96 lbl->join_for_break_ = NULL;
95 lbl->join_for_continue_ = NULL; 97 lbl->join_for_continue_ = NULL;
96 } 98 }
97 }; 99 };
98 100
99 101
102 // Helper to create a parameter stub from an actual argument.
103 static Definition* CreateParameterStub(intptr_t i,
104 Value* argument,
105 FlowGraph* graph) {
106 ConstantInstr* constant = argument->definition()->AsConstant();
107 if (constant != NULL) {
108 return new ConstantInstr(constant->value());
109 } else {
110 return new ParameterInstr(i, graph->graph_entry());
111 }
112 }
113
114
115 // Helper to get the default value of a formal parameter.
116 static ConstantInstr* GetDefaultValue(intptr_t i,
117 const ParsedFunction& parsed_function) {
118 return new ConstantInstr(Object::ZoneHandle(
119 parsed_function.default_parameter_values().At(i)));
120 }
121
122
123 // Pair of an argument name and its value.
124 struct NamedArgument : ZoneAllocated {
Kevin Millikin (Google) 2012/10/23 11:34:42 It should work to make this ValueObject.
zerny-google 2012/10/23 13:03:42 Done.
125 public:
126 String* name;
127 Value* value;
128 NamedArgument(String* name, Value* value)
129 : name(name), value(value) { }
130 };
131
132
100 // A collection of call sites to consider for inlining. 133 // A collection of call sites to consider for inlining.
101 class CallSites : public FlowGraphVisitor { 134 class CallSites : public FlowGraphVisitor {
102 public: 135 public:
103 explicit CallSites(FlowGraph* flow_graph) 136 explicit CallSites(FlowGraph* flow_graph)
104 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order. 137 : FlowGraphVisitor(flow_graph->postorder()), // We don't use this order.
105 static_calls_(), 138 static_calls_(),
106 closure_calls_(), 139 closure_calls_(),
107 instance_calls_() { } 140 instance_calls_() { }
108 141
109 GrowableArray<StaticCallInstr*>* static_calls() { 142 GrowableArray<StaticCallInstr*>* static_calls() {
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
207 240
208 bool inlined() const { return inlined_; } 241 bool inlined() const { return inlined_; }
209 242
210 double GrowthFactor() const { 243 double GrowthFactor() const {
211 return static_cast<double>(inlined_size_) / 244 return static_cast<double>(inlined_size_) /
212 static_cast<double>(initial_size_); 245 static_cast<double>(initial_size_);
213 } 246 }
214 247
215 private: 248 private:
216 bool TryInlining(const Function& function, 249 bool TryInlining(const Function& function,
250 const Array& argument_names,
217 GrowableArray<Value*>* arguments, 251 GrowableArray<Value*>* arguments,
218 Definition* call) { 252 Definition* call) {
219 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", 253 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n",
220 function.ToCString(), 254 function.ToCString(),
221 function.deoptimization_counter())); 255 function.deoptimization_counter()));
222 256
223 // Abort if the inlinable bit on the function is low. 257 // Abort if the inlinable bit on the function is low.
224 if (!function.IsInlineable()) { 258 if (!function.IsInlineable()) {
225 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); 259 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n"));
226 return false; 260 return false;
227 } 261 }
228 262
229 // Abort if the callee has optional parameters.
230 if (function.HasOptionalParameters()) {
231 TRACE_INLINING(OS::Print(" Bailout: optional parameters\n"));
232 return false;
233 }
234
235 // Assuming no optional parameters the actual/formal count should match.
236 ASSERT(arguments->length() == function.num_fixed_parameters());
237
238 // Abort if this function has deoptimized too much. 263 // Abort if this function has deoptimized too much.
239 if (function.deoptimization_counter() >= 264 if (function.deoptimization_counter() >=
240 FLAG_deoptimization_counter_threshold) { 265 FLAG_deoptimization_counter_threshold) {
241 function.set_is_inlinable(false); 266 function.set_is_inlinable(false);
242 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); 267 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n"));
243 return false; 268 return false;
244 } 269 }
245 270
246 // Abort if this is a recursive occurrence. 271 // Abort if this is a recursive occurrence.
247 if (IsCallRecursive(function, call)) { 272 if (IsCallRecursive(function, call)) {
248 function.set_is_inlinable(false); 273 function.set_is_inlinable(false);
249 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); 274 TRACE_INLINING(OS::Print(" Bailout: recursive function\n"));
250 return false; 275 return false;
251 } 276 }
252 277
253 // Abort if the callee has an intrinsic translation. 278 // Abort if the callee has an intrinsic translation.
254 if (Intrinsifier::CanIntrinsify(function)) { 279 if (Intrinsifier::CanIntrinsify(function)) {
255 function.set_is_inlinable(false); 280 function.set_is_inlinable(false);
256 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); 281 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n"));
257 return false; 282 return false;
258 } 283 }
259 284
285 // Abort if we are running legacy support for optional parameters.
286 if (!FLAG_reject_named_argument_as_positional &&
287 function.HasOptionalPositionalParameters() &&
288 (!argument_names.IsNull() && (argument_names.Length() > 0))) {
289 function.set_is_inlinable(false);
290 TRACE_INLINING(OS::Print(
291 " Bailout: named optional positional parameter\n"));
292 return false;
293 }
294
260 Isolate* isolate = Isolate::Current(); 295 Isolate* isolate = Isolate::Current();
261 // Save and clear IC data. 296 // Save and clear IC data.
262 const Array& prev_ic_data = Array::Handle(isolate->ic_data_array()); 297 const Array& prev_ic_data = Array::Handle(isolate->ic_data_array());
263 isolate->set_ic_data_array(Array::null()); 298 isolate->set_ic_data_array(Array::null());
264 // Save and clear deopt id. 299 // Save and clear deopt id.
265 const intptr_t prev_deopt_id = isolate->deopt_id(); 300 const intptr_t prev_deopt_id = isolate->deopt_id();
266 isolate->set_deopt_id(0); 301 isolate->set_deopt_id(0);
267 // Install bailout jump. 302 // Install bailout jump.
268 LongJump* base = isolate->long_jump_base(); 303 LongJump* base = isolate->long_jump_base();
269 LongJump jump; 304 LongJump jump;
(...skipping 30 matching lines...) Expand all
300 // Abort if the callee graph contains control flow. 335 // Abort if the callee graph contains control flow.
301 if (!FLAG_inline_control_flow && 336 if (!FLAG_inline_control_flow &&
302 (callee_graph->preorder().length() != 2)) { 337 (callee_graph->preorder().length() != 2)) {
303 function.set_is_inlinable(false); 338 function.set_is_inlinable(false);
304 isolate->set_long_jump_base(base); 339 isolate->set_long_jump_base(base);
305 isolate->set_ic_data_array(prev_ic_data.raw()); 340 isolate->set_ic_data_array(prev_ic_data.raw());
306 TRACE_INLINING(OS::Print(" Bailout: control flow\n")); 341 TRACE_INLINING(OS::Print(" Bailout: control flow\n"));
307 return false; 342 return false;
308 } 343 }
309 344
345 // The parameter stubs are a copy of the actual arguments providing
346 // concrete information about the values, for example constant values,
347 // without linking between the caller and callee graphs.
348 // TODO(zerny): Put more information in the stubs, eg, type information.
349 GrowableArray<Definition*> param_stubs(function.NumParameters());
350
351 // Create a parameter stub for each fixed positional parameter.
352 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) {
353 param_stubs.Add(CreateParameterStub(i, (*arguments)[i], callee_graph));
354 }
355
356 // If the callee has optional parameters, rebuild the argument and stub
357 // arrays so that actual arguments are in one-to-one with the formal
358 // parameters.
359 if (function.HasOptionalParameters()) {
360 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n"));
361 AdjustForOptionalParameters(*parsed_function,
362 argument_names,
363 arguments,
364 &param_stubs,
365 callee_graph);
366 // Add a bogus parameter at the end for the (unused) argument descriptor
367 // slot. The parser allocates an extra slot between locals and
368 // parameters to hold the argument descriptor in case it escapes. We
369 // currently bailout if there are argument test expressions or escaping
370 // variables so this parameter and the stack slot are not used.
371 if (parsed_function->GetSavedArgumentsDescriptorVar() != NULL) {
372 param_stubs.Add(new ParameterInstr(
373 function.NumParameters(), callee_graph->graph_entry()));
374 }
375 }
376
377 // After treating optional parameters the actual/formal count must match.
378 ASSERT(arguments->length() == function.NumParameters());
379 ASSERT(param_stubs.length() == callee_graph->parameter_count());
380
310 { 381 {
311 TimerScope timer(FLAG_compiler_stats, 382 TimerScope timer(FLAG_compiler_stats,
312 &CompilerStats::graphinliner_ssa_timer, 383 &CompilerStats::graphinliner_ssa_timer,
313 isolate); 384 isolate);
314 // Compute SSA on the callee graph, catching bailouts. 385 // Compute SSA on the callee graph, catching bailouts.
315 callee_graph->ComputeSSA(next_ssa_temp_index_); 386 callee_graph->ComputeSSA(next_ssa_temp_index_, &param_stubs);
316 callee_graph->ComputeUseLists(); 387 callee_graph->ComputeUseLists();
317 } 388 }
318 389
319 { 390 {
320 TimerScope timer(FLAG_compiler_stats, 391 TimerScope timer(FLAG_compiler_stats,
321 &CompilerStats::graphinliner_opt_timer, 392 &CompilerStats::graphinliner_opt_timer,
322 isolate); 393 isolate);
323 // TODO(zerny): Do more optimization passes on the callee graph. 394 // TODO(zerny): Do more optimization passes on the callee graph.
324 FlowGraphOptimizer optimizer(callee_graph); 395 FlowGraphOptimizer optimizer(callee_graph);
325 optimizer.ApplyICData(); 396 optimizer.ApplyICData();
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 caller_graph_->InlineCall(call, callee_graph); 430 caller_graph_->InlineCall(call, callee_graph);
360 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); 431 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number();
361 432
362 // Remove push arguments of the call. 433 // Remove push arguments of the call.
363 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { 434 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) {
364 PushArgumentInstr* push = call->ArgumentAt(i); 435 PushArgumentInstr* push = call->ArgumentAt(i);
365 push->ReplaceUsesWith(push->value()->definition()); 436 push->ReplaceUsesWith(push->value()->definition());
366 push->RemoveFromGraph(); 437 push->RemoveFromGraph();
367 } 438 }
368 439
369 // Replace formal parameters with actuals. 440 // Replace each stub with the actual argument or the caller's constant.
370 intptr_t arg_index = 0; 441 // Nulls denote optional parameters for which no actual was given.
442 for (intptr_t i = 0; i < arguments->length(); ++i) {
443 Definition* stub = param_stubs[i];
444 Value* actual = (*arguments)[i];
445 if (actual != NULL) stub->ReplaceUsesWith(actual->definition());
446 }
447
448 // Replace remaining constants with uses by constants in the caller's
449 // initial definitions.
371 GrowableArray<Definition*>* defns = 450 GrowableArray<Definition*>* defns =
372 callee_graph->graph_entry()->initial_definitions(); 451 callee_graph->graph_entry()->initial_definitions();
373 for (intptr_t i = 0; i < defns->length(); ++i) { 452 for (intptr_t i = 0; i < defns->length(); ++i) {
374 ParameterInstr* param = (*defns)[i]->AsParameter(); 453 ConstantInstr* constant = (*defns)[i]->AsConstant();
375 if (param != NULL) { 454 if (constant == NULL ||
376 param->ReplaceUsesWith((*arguments)[arg_index++]->definition()); 455 ((constant->input_use_list() == NULL) &&
456 (constant->env_use_list() == NULL))) {
457 continue;
377 } 458 }
459 constant->ReplaceUsesWith(
460 caller_graph_->AddConstantToInitialDefinitions(constant->value()));
378 } 461 }
379 ASSERT(arg_index == arguments->length());
380
381 // Replace callee's null constant with caller's null constant.
382 callee_graph->graph_entry()->constant_null()->ReplaceUsesWith(
383 caller_graph_->graph_entry()->constant_null());
384 } 462 }
385 463
386 TRACE_INLINING(OS::Print(" Success\n")); 464 TRACE_INLINING(OS::Print(" Success\n"));
387 465
388 // Add the function to the cache. 466 // Add the function to the cache.
389 if (!in_cache) function_cache.Add(parsed_function); 467 if (!in_cache) function_cache.Add(parsed_function);
390 468
391 // Check that inlining maintains use lists. 469 // Check that inlining maintains use lists.
392 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->ValidateUseLists()); 470 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->ValidateUseLists());
393 471
394 // Build succeeded so we restore the bailout jump. 472 // Build succeeded so we restore the bailout jump.
395 inlined_ = true; 473 inlined_ = true;
396 inlined_size_ += size; 474 inlined_size_ += size;
397 isolate->set_long_jump_base(base); 475 isolate->set_long_jump_base(base);
398 isolate->set_deopt_id(prev_deopt_id); 476 isolate->set_deopt_id(prev_deopt_id);
399 isolate->set_ic_data_array(prev_ic_data.raw()); 477 isolate->set_ic_data_array(prev_ic_data.raw());
400 return true; 478 return true;
401 } else { 479 } else {
402 Error& error = Error::Handle(); 480 Error& error = Error::Handle();
403 error = isolate->object_store()->sticky_error(); 481 error = isolate->object_store()->sticky_error();
404 isolate->object_store()->clear_sticky_error(); 482 isolate->object_store()->clear_sticky_error();
405 isolate->set_long_jump_base(base); 483 isolate->set_long_jump_base(base);
406 isolate->set_deopt_id(prev_deopt_id); 484 isolate->set_deopt_id(prev_deopt_id);
407 isolate->set_ic_data_array(prev_ic_data.raw()); 485 isolate->set_ic_data_array(prev_ic_data.raw());
408 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); 486 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString()));
409 return false; 487 return false;
410 } 488 }
411 } 489 }
412 490
413 // Parse a function reusing the cache if possible. Returns true if the 491 // Parse a function reusing the cache if possible.
414 // function was in the cache.
415 ParsedFunction* ParseFunction(const Function& function, bool* in_cache) { 492 ParsedFunction* ParseFunction(const Function& function, bool* in_cache) {
416 // TODO(zerny): Use a hash map for the cache. 493 // TODO(zerny): Use a hash map for the cache.
417 for (intptr_t i = 0; i < function_cache.length(); ++i) { 494 for (intptr_t i = 0; i < function_cache.length(); ++i) {
418 ParsedFunction* parsed_function = function_cache[i]; 495 ParsedFunction* parsed_function = function_cache[i];
419 if (parsed_function->function().raw() == function.raw()) { 496 if (parsed_function->function().raw() == function.raw()) {
420 *in_cache = true; 497 *in_cache = true;
421 SourceLabelResetter reset; 498 SourceLabelResetter reset;
422 parsed_function->node_sequence()->Visit(&reset); 499 parsed_function->node_sequence()->Visit(&reset);
423 return parsed_function; 500 return parsed_function;
424 } 501 }
425 } 502 }
426 *in_cache = false; 503 *in_cache = false;
427 ParsedFunction* parsed_function = new ParsedFunction(function); 504 ParsedFunction* parsed_function = new ParsedFunction(function);
428 Parser::ParseFunction(parsed_function); 505 Parser::ParseFunction(parsed_function);
429 parsed_function->AllocateVariables(); 506 parsed_function->AllocateVariables();
430 return parsed_function; 507 return parsed_function;
431 } 508 }
432 509
433 void InlineStaticCalls() { 510 void InlineStaticCalls() {
434 const GrowableArray<StaticCallInstr*>& calls = 511 const GrowableArray<StaticCallInstr*>& calls =
435 *inlining_call_sites_->static_calls(); 512 *inlining_call_sites_->static_calls();
436 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length())); 513 TRACE_INLINING(OS::Print(" Static Calls (%d)\n", calls.length()));
437 for (intptr_t i = 0; i < calls.length(); ++i) { 514 for (intptr_t i = 0; i < calls.length(); ++i) {
438 StaticCallInstr* call = calls[i]; 515 StaticCallInstr* call = calls[i];
439 GrowableArray<Value*> arguments(call->ArgumentCount()); 516 GrowableArray<Value*> arguments(call->ArgumentCount());
440 for (int i = 0; i < call->ArgumentCount(); ++i) { 517 for (int i = 0; i < call->ArgumentCount(); ++i) {
441 arguments.Add(call->ArgumentAt(i)->value()); 518 arguments.Add(call->ArgumentAt(i)->value());
442 } 519 }
443 TryInlining(call->function(), &arguments, call); 520 TryInlining(call->function(), call->argument_names(), &arguments, call);
444 } 521 }
445 } 522 }
446 523
447 void InlineClosureCalls() { 524 void InlineClosureCalls() {
448 const GrowableArray<ClosureCallInstr*>& calls = 525 const GrowableArray<ClosureCallInstr*>& calls =
449 *inlining_call_sites_->closure_calls(); 526 *inlining_call_sites_->closure_calls();
450 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length())); 527 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length()));
451 for (intptr_t i = 0; i < calls.length(); ++i) { 528 for (intptr_t i = 0; i < calls.length(); ++i) {
452 ClosureCallInstr* call = calls[i]; 529 ClosureCallInstr* call = calls[i];
453 // Find the closure of the callee. 530 // Find the closure of the callee.
454 ASSERT(call->ArgumentCount() > 0); 531 ASSERT(call->ArgumentCount() > 0);
455 const CreateClosureInstr* closure = 532 const CreateClosureInstr* closure =
456 call->ArgumentAt(0)->value()->definition()->AsCreateClosure(); 533 call->ArgumentAt(0)->value()->definition()->AsCreateClosure();
457 if (closure == NULL) { 534 if (closure == NULL) {
458 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); 535 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n"));
459 continue; 536 continue;
460 } 537 }
461 GrowableArray<Value*> arguments(call->ArgumentCount() - 1); 538 GrowableArray<Value*> arguments(call->ArgumentCount() - 1);
462 for (int i = 1; i < call->ArgumentCount(); ++i) { 539 for (int i = 1; i < call->ArgumentCount(); ++i) {
463 arguments.Add(call->ArgumentAt(i)->value()); 540 arguments.Add(call->ArgumentAt(i)->value());
464 } 541 }
465 TryInlining(closure->function(), &arguments, call); 542 TryInlining(closure->function(),
543 call->argument_names(),
544 &arguments,
545 call);
466 } 546 }
467 } 547 }
468 548
469 void InlineInstanceCalls() { 549 void InlineInstanceCalls() {
470 const GrowableArray<PolymorphicInstanceCallInstr*>& calls = 550 const GrowableArray<PolymorphicInstanceCallInstr*>& calls =
471 *inlining_call_sites_->instance_calls(); 551 *inlining_call_sites_->instance_calls();
472 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", 552 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n",
473 calls.length())); 553 calls.length()));
474 for (intptr_t i = 0; i < calls.length(); ++i) { 554 for (intptr_t i = 0; i < calls.length(); ++i) {
475 PolymorphicInstanceCallInstr* instr = calls[i]; 555 PolymorphicInstanceCallInstr* instr = calls[i];
476 const ICData& ic_data = instr->ic_data(); 556 const ICData& ic_data = instr->ic_data();
477 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); 557 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
478 if (instr->with_checks()) { 558 if (instr->with_checks()) {
479 TRACE_INLINING(OS::Print( 559 TRACE_INLINING(OS::Print(
480 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n", 560 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n",
481 target.ToCString(), 561 target.ToCString(),
482 target.deoptimization_counter(), 562 target.deoptimization_counter(),
483 ic_data.NumberOfChecks())); 563 ic_data.NumberOfChecks()));
484 continue; 564 continue;
485 } 565 }
486 GrowableArray<Value*> arguments(instr->ArgumentCount()); 566 GrowableArray<Value*> arguments(instr->ArgumentCount());
487 for (int i = 0; i < instr->ArgumentCount(); ++i) { 567 for (int i = 0; i < instr->ArgumentCount(); ++i) {
488 arguments.Add(instr->ArgumentAt(i)->value()); 568 arguments.Add(instr->ArgumentAt(i)->value());
489 } 569 }
490 TryInlining(target, &arguments, instr); 570 TryInlining(target,
571 instr->instance_call()->argument_names(),
572 &arguments,
573 instr);
491 } 574 }
492 } 575 }
493 576
577 void AdjustForOptionalParameters(const ParsedFunction& parsed_function,
578 const Array& argument_names,
579 GrowableArray<Value*>* arguments,
580 GrowableArray<Definition*>* param_stubs,
581 FlowGraph* callee_graph) {
582 const Function& function = parsed_function.function();
583 // The language and this code does not support both optional positional
584 // and optional named parameters for the same function.
585 ASSERT(!function.HasOptionalPositionalParameters() ||
586 !function.HasOptionalNamedParameters());
587
588 intptr_t arg_count = arguments->length();
589 intptr_t param_count = function.NumParameters();
590 intptr_t fixed_param_count = function.num_fixed_parameters();
591 ASSERT(fixed_param_count <= arg_count);
592 ASSERT(arg_count <= param_count);
593
594 if (function.HasOptionalPositionalParameters()) {
595 // Create a stub for each optional positional parameters with an actual.
596 for (intptr_t i = fixed_param_count; i < arg_count; ++i) {
597 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph));
598 }
599 ASSERT(function.NumOptionalPositionalParameters() ==
600 (param_count - fixed_param_count));
601 // For each optional positional parameter without an actual, add its
602 // default value.
603 for (intptr_t i = arg_count - fixed_param_count;
Kevin Millikin (Google) 2012/10/23 11:34:42 I think it's a bit weird to adjust the initial val
zerny-google 2012/10/23 13:03:42 Done.
604 i < param_count - fixed_param_count;
605 ++i) {
606 const Object& object =
607 Object::ZoneHandle(
608 parsed_function.default_parameter_values().At(i));
609 ConstantInstr* constant = new ConstantInstr(object);
610 arguments->Add(NULL);
611 param_stubs->Add(constant);
612 }
613 return;
614 }
615
616 ASSERT(function.HasOptionalNamedParameters());
617
618 // Passed arguments must match fixed parameters plus named arguments.
619 intptr_t argument_names_count =
620 (argument_names.IsNull()) ? 0 : argument_names.Length();
621 ASSERT(arg_count == (fixed_param_count + argument_names_count));
622
623 // Fast path when no optional named parameters are given.
624 if (argument_names_count == 0) {
625 for (intptr_t i = 0; i < param_count - fixed_param_count; i++) {
626 arguments->Add(NULL);
627 param_stubs->Add(GetDefaultValue(i, parsed_function));
628 }
629 return;
630 }
631
632 // Otherwise, build a collection of name/argument pairs.
633 GrowableArray<NamedArgument*> named_args(argument_names_count);
634 for (intptr_t i = 0; i < argument_names.Length(); ++i) {
635 String& arg_name = String::Handle(Isolate::Current());
636 arg_name ^= argument_names.At(i);
637 named_args.Add(
638 new NamedArgument(&arg_name, (*arguments)[i + fixed_param_count]));
639 }
640
641 // Truncate the arguments array to just fixed parameters.
642 arguments->TruncateTo(fixed_param_count);
643
644 // For each optional named parameter, add the actual argument or its
645 // default if no argument is passed.
646 for (intptr_t i = fixed_param_count; i < param_count; i++) {
Kevin Millikin (Google) 2012/10/23 11:34:42 There's a mix of ++i and i++ in loops in this func
zerny-google 2012/10/23 13:03:42 Done.
647 String& param_name = String::Handle(function.ParameterNameAt(i));
648 // Search for and add the named argument.
649 Value* arg = NULL;
650 for (intptr_t j = 0; j < named_args.length(); j++) {
651 if (param_name.Equals(*named_args[j]->name)) {
652 arg = named_args[j]->value;
653 break;
654 }
655 }
656 arguments->Add(arg);
657 // Create a stub parameter for the named argument or its default.
658 if (arg != NULL) {
659 param_stubs->Add(CreateParameterStub(i, arg, callee_graph));
660 } else {
661 param_stubs->Add(
662 GetDefaultValue(i - fixed_param_count, parsed_function));
663 }
664 }
665 }
666
667
494 FlowGraph* caller_graph_; 668 FlowGraph* caller_graph_;
495 intptr_t next_ssa_temp_index_; 669 intptr_t next_ssa_temp_index_;
496 bool inlined_; 670 bool inlined_;
497 intptr_t initial_size_; 671 intptr_t initial_size_;
498 intptr_t inlined_size_; 672 intptr_t inlined_size_;
499 intptr_t inlining_depth_; 673 intptr_t inlining_depth_;
500 CallSites* collected_call_sites_; 674 CallSites* collected_call_sites_;
501 CallSites* inlining_call_sites_; 675 CallSites* inlining_call_sites_;
502 GrowableArray<ParsedFunction*> function_cache; 676 GrowableArray<ParsedFunction*> function_cache;
503 677
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
535 OS::Print("After Inlining of %s\n", flow_graph_-> 709 OS::Print("After Inlining of %s\n", flow_graph_->
536 parsed_function().function().ToFullyQualifiedCString()); 710 parsed_function().function().ToFullyQualifiedCString());
537 FlowGraphPrinter printer(*flow_graph_); 711 FlowGraphPrinter printer(*flow_graph_);
538 printer.PrintBlocks(); 712 printer.PrintBlocks();
539 } 713 }
540 } 714 }
541 } 715 }
542 } 716 }
543 717
544 } // namespace dart 718 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_builder.cc ('k') | runtime/vm/intermediate_language.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698