Chromium Code Reviews| 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/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 341 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 352 } | 352 } |
| 353 | 353 |
| 354 bool inlined() const { return inlined_; } | 354 bool inlined() const { return inlined_; } |
| 355 | 355 |
| 356 double GrowthFactor() const { | 356 double GrowthFactor() const { |
| 357 return static_cast<double>(inlined_size_) / | 357 return static_cast<double>(inlined_size_) / |
| 358 static_cast<double>(initial_size_); | 358 static_cast<double>(initial_size_); |
| 359 } | 359 } |
| 360 | 360 |
| 361 private: | 361 private: |
| 362 struct InlinedCallData { | |
| 363 public: | |
| 364 InlinedCallData(Definition* call, GrowableArray<Value*>* arguments) | |
| 365 : call(call), | |
| 366 arguments(arguments), | |
| 367 callee_graph(NULL), | |
| 368 parameter_stubs(NULL), | |
| 369 exit_collector(NULL) { } | |
| 370 | |
| 371 Definition* call; | |
| 372 GrowableArray<Value*>* arguments; | |
| 373 FlowGraph* callee_graph; | |
| 374 ZoneGrowableArray<Definition*>* parameter_stubs; | |
| 375 InlineExitCollector* exit_collector; | |
| 376 }; | |
| 377 | |
| 362 bool TryInlining(const Function& function, | 378 bool TryInlining(const Function& function, |
| 363 const Array& argument_names, | 379 const Array& argument_names, |
| 364 GrowableArray<Value*>* arguments, | 380 InlinedCallData* call_data) { |
| 365 Definition* call) { | |
| 366 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 381 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", |
| 367 function.ToCString(), | 382 function.ToCString(), |
| 368 function.deoptimization_counter())); | 383 function.deoptimization_counter())); |
| 369 | 384 |
| 370 // Abort if the inlinable bit on the function is low. | 385 // Abort if the inlinable bit on the function is low. |
| 371 if (!function.IsInlineable()) { | 386 if (!function.IsInlineable()) { |
| 372 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); | 387 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); |
| 373 return false; | 388 return false; |
| 374 } | 389 } |
| 375 | 390 |
| 376 // Abort if this function has deoptimized too much. | 391 // Abort if this function has deoptimized too much. |
| 377 if (function.deoptimization_counter() >= | 392 if (function.deoptimization_counter() >= |
| 378 FLAG_deoptimization_counter_threshold) { | 393 FLAG_deoptimization_counter_threshold) { |
| 379 function.set_is_inlinable(false); | 394 function.set_is_inlinable(false); |
| 380 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 395 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 381 return false; | 396 return false; |
| 382 } | 397 } |
| 383 | 398 |
| 399 GrowableArray<Value*>* arguments = call_data->arguments; | |
| 384 const intptr_t constant_arguments = CountConstants(*arguments); | 400 const intptr_t constant_arguments = CountConstants(*arguments); |
| 385 if (!ShouldWeInline(function.optimized_instruction_count(), | 401 if (!ShouldWeInline(function.optimized_instruction_count(), |
| 386 function.optimized_call_site_count(), | 402 function.optimized_call_site_count(), |
| 387 constant_arguments)) { | 403 constant_arguments)) { |
| 388 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 404 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 389 "code size: %"Pd", " | 405 "code size: %"Pd", " |
| 390 "call sites: %"Pd", " | 406 "call sites: %"Pd", " |
| 391 "const args: %"Pd"\n", | 407 "const args: %"Pd"\n", |
| 392 function.optimized_instruction_count(), | 408 function.optimized_instruction_count(), |
| 393 function.optimized_call_site_count(), | 409 function.optimized_call_site_count(), |
| 394 constant_arguments)); | 410 constant_arguments)); |
| 395 return false; | 411 return false; |
| 396 } | 412 } |
| 397 | 413 |
| 398 // Abort if this is a recursive occurrence. | 414 // Abort if this is a recursive occurrence. |
| 415 Definition* call = call_data->call; | |
| 399 if (!FLAG_inline_recursive && IsCallRecursive(function, call)) { | 416 if (!FLAG_inline_recursive && IsCallRecursive(function, call)) { |
| 400 function.set_is_inlinable(false); | 417 function.set_is_inlinable(false); |
| 401 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 418 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 402 return false; | 419 return false; |
| 403 } | 420 } |
| 404 | 421 |
| 405 // Abort if the callee has an intrinsic translation. | 422 // Abort if the callee has an intrinsic translation. |
| 406 if (Intrinsifier::CanIntrinsify(function)) { | 423 if (Intrinsifier::CanIntrinsify(function)) { |
| 407 function.set_is_inlinable(false); | 424 function.set_is_inlinable(false); |
| 408 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); | 425 TRACE_INLINING(OS::Print(" Bailout: can intrinsify\n")); |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 432 } | 449 } |
| 433 | 450 |
| 434 // Load IC data for the callee. | 451 // Load IC data for the callee. |
| 435 if (function.HasCode()) { | 452 if (function.HasCode()) { |
| 436 const Code& unoptimized_code = | 453 const Code& unoptimized_code = |
| 437 Code::Handle(function.unoptimized_code()); | 454 Code::Handle(function.unoptimized_code()); |
| 438 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); | 455 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); |
| 439 } | 456 } |
| 440 | 457 |
| 441 // Build the callee graph. | 458 // Build the callee graph. |
| 442 InliningContext inlining_context(caller_graph_, call); | 459 InlineExitCollector* exit_collector = |
| 443 FlowGraphBuilder builder(*parsed_function, &inlining_context); | 460 new InlineExitCollector(caller_graph_, call); |
| 461 FlowGraphBuilder builder(*parsed_function, exit_collector); | |
| 444 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 462 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 445 FlowGraph* callee_graph; | 463 FlowGraph* callee_graph; |
| 446 { | 464 { |
| 447 TimerScope timer(FLAG_compiler_stats, | 465 TimerScope timer(FLAG_compiler_stats, |
| 448 &CompilerStats::graphinliner_build_timer, | 466 &CompilerStats::graphinliner_build_timer, |
| 449 isolate); | 467 isolate); |
| 450 callee_graph = builder.BuildGraph(); | 468 callee_graph = builder.BuildGraph(); |
| 451 } | 469 } |
| 452 | 470 |
| 453 // The parameter stubs are a copy of the actual arguments providing | 471 // The parameter stubs are a copy of the actual arguments providing |
| 454 // concrete information about the values, for example constant values, | 472 // concrete information about the values, for example constant values, |
| 455 // without linking between the caller and callee graphs. | 473 // without linking between the caller and callee graphs. |
| 456 // TODO(zerny): Put more information in the stubs, eg, type information. | 474 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 457 GrowableArray<Definition*> param_stubs(function.NumParameters()); | 475 ZoneGrowableArray<Definition*>* param_stubs = |
| 476 new ZoneGrowableArray<Definition*>(function.NumParameters()); | |
| 458 | 477 |
| 459 // Create a parameter stub for each fixed positional parameter. | 478 // Create a parameter stub for each fixed positional parameter. |
| 460 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 479 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 461 param_stubs.Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 480 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 462 } | 481 } |
| 463 | 482 |
| 464 // If the callee has optional parameters, rebuild the argument and stub | 483 // If the callee has optional parameters, rebuild the argument and stub |
| 465 // arrays so that actual arguments are in one-to-one with the formal | 484 // arrays so that actual arguments are in one-to-one with the formal |
| 466 // parameters. | 485 // parameters. |
| 467 if (function.HasOptionalParameters()) { | 486 if (function.HasOptionalParameters()) { |
| 468 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); | 487 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); |
| 469 AdjustForOptionalParameters(*parsed_function, | 488 AdjustForOptionalParameters(*parsed_function, |
| 470 argument_names, | 489 argument_names, |
| 471 arguments, | 490 arguments, |
| 472 ¶m_stubs, | 491 param_stubs, |
| 473 callee_graph); | 492 callee_graph); |
| 474 // Add a bogus parameter at the end for the (unused) arguments | 493 // Add a bogus parameter at the end for the (unused) arguments |
| 475 // descriptor slot. The parser allocates an extra slot between | 494 // descriptor slot. The parser allocates an extra slot between |
| 476 // locals and parameters to hold the arguments descriptor in case it | 495 // locals and parameters to hold the arguments descriptor in case it |
| 477 // escapes. We currently bailout if there are argument test | 496 // escapes. We currently bailout if there are argument test |
| 478 // expressions or escaping variables so this parameter and the stack | 497 // expressions or escaping variables so this parameter and the stack |
| 479 // slot are not used. | 498 // slot are not used. |
| 480 if (parsed_function->GetSavedArgumentsDescriptorVar() != NULL) { | 499 if (parsed_function->GetSavedArgumentsDescriptorVar() != NULL) { |
| 481 param_stubs.Add(new ParameterInstr( | 500 param_stubs->Add(new ParameterInstr( |
| 482 function.NumParameters(), callee_graph->graph_entry())); | 501 function.NumParameters(), callee_graph->graph_entry())); |
| 483 } | 502 } |
| 484 } | 503 } |
| 485 | 504 |
| 486 // After treating optional parameters the actual/formal count must match. | 505 // After treating optional parameters the actual/formal count must match. |
| 487 ASSERT(arguments->length() == function.NumParameters()); | 506 ASSERT(arguments->length() == function.NumParameters()); |
| 488 ASSERT(param_stubs.length() == callee_graph->parameter_count()); | 507 ASSERT(param_stubs->length() == callee_graph->parameter_count()); |
| 489 | 508 |
| 490 { | 509 { |
| 491 TimerScope timer(FLAG_compiler_stats, | 510 TimerScope timer(FLAG_compiler_stats, |
| 492 &CompilerStats::graphinliner_ssa_timer, | 511 &CompilerStats::graphinliner_ssa_timer, |
| 493 isolate); | 512 isolate); |
| 494 // Compute SSA on the callee graph, catching bailouts. | 513 // Compute SSA on the callee graph, catching bailouts. |
| 495 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), | 514 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), |
| 496 ¶m_stubs); | 515 param_stubs); |
| 497 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 516 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 498 } | 517 } |
| 499 | 518 |
| 500 { | 519 { |
| 501 TimerScope timer(FLAG_compiler_stats, | 520 TimerScope timer(FLAG_compiler_stats, |
| 502 &CompilerStats::graphinliner_opt_timer, | 521 &CompilerStats::graphinliner_opt_timer, |
| 503 isolate); | 522 isolate); |
| 504 // TODO(zerny): Do more optimization passes on the callee graph. | 523 // TODO(zerny): Do more optimization passes on the callee graph. |
| 505 FlowGraphOptimizer optimizer(callee_graph, guarded_fields_); | 524 FlowGraphOptimizer optimizer(callee_graph, guarded_fields_); |
| 506 optimizer.ApplyICData(); | 525 optimizer.ApplyICData(); |
| 507 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 526 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 508 } | 527 } |
| 509 | 528 |
| 510 if (FLAG_trace_inlining && | 529 if (FLAG_trace_inlining && |
| 511 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 530 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
| 512 OS::Print("Callee graph for inlining %s\n", | 531 OS::Print("Callee graph for inlining %s\n", |
| 513 function.ToFullyQualifiedCString()); | 532 function.ToFullyQualifiedCString()); |
| 514 FlowGraphPrinter printer(*callee_graph); | 533 FlowGraphPrinter printer(*callee_graph); |
| 515 printer.PrintBlocks(); | 534 printer.PrintBlocks(); |
| 516 } | 535 } |
| 517 | 536 |
| 518 // Collect information about the call site and caller graph. | 537 // Collect information about the call site and caller graph. |
| 519 // TODO(zerny): Do this after CP and dead code elimination. | 538 // TODO(zerny): Do this after CP and dead code elimination. |
| 520 intptr_t constants_count = 0; | 539 intptr_t constants_count = 0; |
| 521 for (intptr_t i = 0; i < param_stubs.length(); ++i) { | 540 for (intptr_t i = 0; i < param_stubs->length(); ++i) { |
| 522 if (param_stubs[i]->IsConstant()) ++constants_count; | 541 if ((*param_stubs)[i]->IsConstant()) ++constants_count; |
| 523 } | 542 } |
| 524 GraphInfoCollector info; | 543 GraphInfoCollector info; |
| 525 info.Collect(*callee_graph); | 544 info.Collect(*callee_graph); |
| 526 const intptr_t size = info.instruction_count(); | 545 const intptr_t size = info.instruction_count(); |
| 527 | 546 |
| 528 function.set_optimized_instruction_count(size); | 547 function.set_optimized_instruction_count(size); |
| 529 function.set_optimized_call_site_count(info.call_site_count()); | 548 function.set_optimized_call_site_count(info.call_site_count()); |
| 530 | 549 |
| 531 // Use heuristics do decide if this call should be inlined. | 550 // Use heuristics do decide if this call should be inlined. |
| 532 if (!ShouldWeInline(size, | 551 if (!ShouldWeInline(size, |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 549 info.call_site_count(), | 568 info.call_site_count(), |
| 550 constants_count)); | 569 constants_count)); |
| 551 return false; | 570 return false; |
| 552 } | 571 } |
| 553 | 572 |
| 554 // If depth is less or equal to threshold recursively add call sites. | 573 // If depth is less or equal to threshold recursively add call sites. |
| 555 if (inlining_depth_ < FLAG_inlining_depth_threshold) { | 574 if (inlining_depth_ < FLAG_inlining_depth_threshold) { |
| 556 collected_call_sites_->FindCallSites(callee_graph); | 575 collected_call_sites_->FindCallSites(callee_graph); |
| 557 } | 576 } |
| 558 | 577 |
| 559 { | |
| 560 TimerScope timer(FLAG_compiler_stats, | |
| 561 &CompilerStats::graphinliner_subst_timer, | |
| 562 isolate); | |
| 563 | |
| 564 // Plug result in the caller graph. | |
| 565 inlining_context.ReplaceCall(callee_graph); | |
| 566 | |
| 567 // Replace each stub with the actual argument or the caller's constant. | |
| 568 // Nulls denote optional parameters for which no actual was given. | |
| 569 for (intptr_t i = 0; i < arguments->length(); ++i) { | |
| 570 Definition* stub = param_stubs[i]; | |
| 571 Value* actual = (*arguments)[i]; | |
| 572 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); | |
| 573 } | |
| 574 | |
| 575 // Remove push arguments of the call. | |
| 576 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 577 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 578 push->ReplaceUsesWith(push->value()->definition()); | |
| 579 push->RemoveFromGraph(); | |
| 580 } | |
| 581 | |
| 582 // Replace remaining constants with uses by constants in the caller's | |
| 583 // initial definitions. | |
| 584 GrowableArray<Definition*>* defns = | |
| 585 callee_graph->graph_entry()->initial_definitions(); | |
| 586 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 587 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 588 if ((constant != NULL) && constant->HasUses()) { | |
| 589 constant->ReplaceUsesWith( | |
| 590 caller_graph_->AddConstantToInitialDefinitions( | |
| 591 constant->value())); | |
| 592 } | |
| 593 } | |
| 594 } | |
| 595 | |
| 596 TRACE_INLINING(OS::Print(" Success\n")); | |
| 597 | |
| 598 // Add the function to the cache. | 578 // Add the function to the cache. |
| 599 if (!in_cache) function_cache_.Add(parsed_function); | 579 if (!in_cache) function_cache_.Add(parsed_function); |
| 600 | 580 |
| 601 // Check that inlining maintains use lists. | |
| 602 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists()); | |
| 603 | |
| 604 // Build succeeded so we restore the bailout jump. | 581 // Build succeeded so we restore the bailout jump. |
| 605 inlined_ = true; | 582 inlined_ = true; |
| 606 inlined_size_ += size; | 583 inlined_size_ += size; |
| 607 isolate->set_long_jump_base(base); | 584 isolate->set_long_jump_base(base); |
| 608 isolate->set_deopt_id(prev_deopt_id); | 585 isolate->set_deopt_id(prev_deopt_id); |
| 609 isolate->set_ic_data_array(prev_ic_data.raw()); | 586 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 587 | |
| 588 call_data->callee_graph = callee_graph; | |
| 589 call_data->parameter_stubs = param_stubs; | |
| 590 call_data->exit_collector = exit_collector; | |
| 591 TRACE_INLINING(OS::Print(" Success\n")); | |
| 610 return true; | 592 return true; |
| 611 } else { | 593 } else { |
| 612 Error& error = Error::Handle(); | 594 Error& error = Error::Handle(); |
| 613 error = isolate->object_store()->sticky_error(); | 595 error = isolate->object_store()->sticky_error(); |
| 614 isolate->object_store()->clear_sticky_error(); | 596 isolate->object_store()->clear_sticky_error(); |
| 615 isolate->set_long_jump_base(base); | 597 isolate->set_long_jump_base(base); |
| 616 isolate->set_deopt_id(prev_deopt_id); | 598 isolate->set_deopt_id(prev_deopt_id); |
| 617 isolate->set_ic_data_array(prev_ic_data.raw()); | 599 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 618 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 600 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 619 return false; | 601 return false; |
| 620 } | 602 } |
| 621 } | 603 } |
| 622 | 604 |
| 605 void InlineCall(InlinedCallData* call_data) { | |
|
srdjan
2013/04/16 16:51:17
call_data is read only in this function, you could
tfarina
2013/04/23 02:05:27
I have addressed this here: https://codereview.chr
| |
| 606 TimerScope timer(FLAG_compiler_stats, | |
| 607 &CompilerStats::graphinliner_subst_timer, | |
| 608 Isolate::Current()); | |
| 609 | |
| 610 // Plug result in the caller graph. | |
| 611 FlowGraph* callee_graph = call_data->callee_graph; | |
| 612 InlineExitCollector* exit_collector = call_data->exit_collector; | |
| 613 exit_collector->PrepareGraphs(callee_graph); | |
| 614 exit_collector->ReplaceCall(callee_graph->graph_entry()->normal_entry()); | |
| 615 | |
| 616 // Replace each stub with the actual argument or the caller's constant. | |
| 617 // Nulls denote optional parameters for which no actual was given. | |
| 618 GrowableArray<Value*>* arguments = call_data->arguments; | |
| 619 for (intptr_t i = 0; i < arguments->length(); ++i) { | |
| 620 Definition* stub = (*call_data->parameter_stubs)[i]; | |
| 621 Value* actual = (*arguments)[i]; | |
| 622 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); | |
| 623 } | |
| 624 | |
| 625 // Remove push arguments of the call. | |
| 626 Definition* call = call_data->call; | |
| 627 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 628 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 629 push->ReplaceUsesWith(push->value()->definition()); | |
| 630 push->RemoveFromGraph(); | |
| 631 } | |
| 632 | |
| 633 // Replace remaining constants with uses by constants in the caller's | |
| 634 // initial definitions. | |
| 635 GrowableArray<Definition*>* defns = | |
| 636 callee_graph->graph_entry()->initial_definitions(); | |
| 637 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 638 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 639 if ((constant != NULL) && constant->HasUses()) { | |
| 640 constant->ReplaceUsesWith( | |
| 641 caller_graph_->AddConstantToInitialDefinitions( | |
| 642 constant->value())); | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 // Check that inlining maintains use lists. | |
| 647 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists()); | |
| 648 } | |
| 649 | |
| 623 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { | 650 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { |
| 624 intptr_t count = 0; | 651 intptr_t count = 0; |
| 625 for (intptr_t i = 0; i < arguments.length(); i++) { | 652 for (intptr_t i = 0; i < arguments.length(); i++) { |
| 626 if (arguments[i]->BindsToConstant()) count++; | 653 if (arguments[i]->BindsToConstant()) count++; |
| 627 } | 654 } |
| 628 return count; | 655 return count; |
| 629 } | 656 } |
| 630 | 657 |
| 631 // Parse a function reusing the cache if possible. | 658 // Parse a function reusing the cache if possible. |
| 632 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 659 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 665 if ((call->ArgumentCount() == 2) && | 692 if ((call->ArgumentCount() == 2) && |
| 666 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { | 693 (!call->PushArgumentAt(1)->value()->BindsToConstant())) { |
| 667 // Do not inline since a non-constant argument was passed. | 694 // Do not inline since a non-constant argument was passed. |
| 668 continue; | 695 continue; |
| 669 } | 696 } |
| 670 } | 697 } |
| 671 GrowableArray<Value*> arguments(call->ArgumentCount()); | 698 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 672 for (int i = 0; i < call->ArgumentCount(); ++i) { | 699 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 673 arguments.Add(call->PushArgumentAt(i)->value()); | 700 arguments.Add(call->PushArgumentAt(i)->value()); |
| 674 } | 701 } |
| 675 TryInlining(call->function(), call->argument_names(), &arguments, call); | 702 InlinedCallData call_data(call, &arguments); |
| 703 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | |
| 704 InlineCall(&call_data); | |
| 705 } | |
| 676 } | 706 } |
| 677 } | 707 } |
| 678 | 708 |
| 679 void InlineClosureCalls() { | 709 void InlineClosureCalls() { |
| 680 const GrowableArray<ClosureCallInstr*>& calls = | 710 const GrowableArray<ClosureCallInstr*>& calls = |
| 681 inlining_call_sites_->closure_calls(); | 711 inlining_call_sites_->closure_calls(); |
| 682 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length())); | 712 TRACE_INLINING(OS::Print(" Closure Calls (%d)\n", calls.length())); |
| 683 for (intptr_t i = 0; i < calls.length(); ++i) { | 713 for (intptr_t i = 0; i < calls.length(); ++i) { |
| 684 ClosureCallInstr* call = calls[i]; | 714 ClosureCallInstr* call = calls[i]; |
| 685 // Find the closure of the callee. | 715 // Find the closure of the callee. |
| 686 ASSERT(call->ArgumentCount() > 0); | 716 ASSERT(call->ArgumentCount() > 0); |
| 687 const CreateClosureInstr* closure = | 717 const CreateClosureInstr* closure = |
| 688 call->ArgumentAt(0)->AsCreateClosure(); | 718 call->ArgumentAt(0)->AsCreateClosure(); |
| 689 if (closure == NULL) { | 719 if (closure == NULL) { |
| 690 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); | 720 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); |
| 691 continue; | 721 continue; |
| 692 } | 722 } |
| 693 GrowableArray<Value*> arguments(call->ArgumentCount()); | 723 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 694 for (int i = 0; i < call->ArgumentCount(); ++i) { | 724 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 695 arguments.Add(call->PushArgumentAt(i)->value()); | 725 arguments.Add(call->PushArgumentAt(i)->value()); |
| 696 } | 726 } |
| 697 TryInlining(closure->function(), | 727 InlinedCallData call_data(call, &arguments); |
| 698 call->argument_names(), | 728 if (TryInlining(closure->function(), |
| 699 &arguments, | 729 call->argument_names(), |
| 700 call); | 730 &call_data)) { |
| 731 InlineCall(&call_data); | |
| 732 } | |
| 701 } | 733 } |
| 702 } | 734 } |
| 703 | 735 |
| 704 void InlineInstanceCalls() { | 736 void InlineInstanceCalls() { |
| 705 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 737 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
| 706 inlining_call_sites_->instance_calls(); | 738 inlining_call_sites_->instance_calls(); |
| 707 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", | 739 TRACE_INLINING(OS::Print(" Polymorphic Instance Calls (%d)\n", |
| 708 call_info.length())); | 740 call_info.length())); |
| 709 for (intptr_t i = 0; i < call_info.length(); ++i) { | 741 for (intptr_t i = 0; i < call_info.length(); ++i) { |
| 710 PolymorphicInstanceCallInstr* instr = call_info[i].call; | 742 PolymorphicInstanceCallInstr* call = call_info[i].call; |
| 711 const ICData& ic_data = instr->ic_data(); | 743 const ICData& ic_data = call->ic_data(); |
| 712 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 744 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 713 if (instr->with_checks()) { | 745 if (call->with_checks()) { |
| 714 TRACE_INLINING(OS::Print( | 746 TRACE_INLINING(OS::Print( |
| 715 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n", | 747 " => %s (deopt count %d)\n Bailout: %"Pd" checks\n", |
| 716 target.ToCString(), | 748 target.ToCString(), |
| 717 target.deoptimization_counter(), | 749 target.deoptimization_counter(), |
| 718 ic_data.NumberOfChecks())); | 750 ic_data.NumberOfChecks())); |
| 719 continue; | 751 continue; |
| 720 } | 752 } |
| 721 if ((call_info[i].ratio * 100) < FLAG_inlining_hotness) { | 753 if ((call_info[i].ratio * 100) < FLAG_inlining_hotness) { |
| 722 TRACE_INLINING(OS::Print( | 754 TRACE_INLINING(OS::Print( |
| 723 " => %s (deopt count %d)\n Bailout: cold %f\n", | 755 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 724 target.ToCString(), | 756 target.ToCString(), |
| 725 target.deoptimization_counter(), | 757 target.deoptimization_counter(), |
| 726 call_info[i].ratio)); | 758 call_info[i].ratio)); |
| 727 continue; | 759 continue; |
| 728 } | 760 } |
| 729 GrowableArray<Value*> arguments(instr->ArgumentCount()); | 761 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 730 for (int arg_i = 0; arg_i < instr->ArgumentCount(); ++arg_i) { | 762 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
| 731 arguments.Add(instr->PushArgumentAt(arg_i)->value()); | 763 arguments.Add(call->PushArgumentAt(arg_i)->value()); |
| 732 } | 764 } |
| 733 TryInlining(target, | 765 InlinedCallData call_data(call, &arguments); |
| 734 instr->instance_call()->argument_names(), | 766 if (TryInlining(target, |
| 735 &arguments, | 767 call->instance_call()->argument_names(), |
| 736 instr); | 768 &call_data)) { |
| 769 InlineCall(&call_data); | |
| 770 } | |
| 737 } | 771 } |
| 738 } | 772 } |
| 739 | 773 |
| 740 void AdjustForOptionalParameters(const ParsedFunction& parsed_function, | 774 void AdjustForOptionalParameters(const ParsedFunction& parsed_function, |
| 741 const Array& argument_names, | 775 const Array& argument_names, |
| 742 GrowableArray<Value*>* arguments, | 776 GrowableArray<Value*>* arguments, |
| 743 GrowableArray<Definition*>* param_stubs, | 777 ZoneGrowableArray<Definition*>* param_stubs, |
| 744 FlowGraph* callee_graph) { | 778 FlowGraph* callee_graph) { |
| 745 const Function& function = parsed_function.function(); | 779 const Function& function = parsed_function.function(); |
| 746 // The language and this code does not support both optional positional | 780 // The language and this code does not support both optional positional |
| 747 // and optional named parameters for the same function. | 781 // and optional named parameters for the same function. |
| 748 ASSERT(!function.HasOptionalPositionalParameters() || | 782 ASSERT(!function.HasOptionalPositionalParameters() || |
| 749 !function.HasOptionalNamedParameters()); | 783 !function.HasOptionalNamedParameters()); |
| 750 | 784 |
| 751 intptr_t arg_count = arguments->length(); | 785 intptr_t arg_count = arguments->length(); |
| 752 intptr_t param_count = function.NumParameters(); | 786 intptr_t param_count = function.NumParameters(); |
| 753 intptr_t fixed_param_count = function.num_fixed_parameters(); | 787 intptr_t fixed_param_count = function.num_fixed_parameters(); |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 887 OS::Print("After Inlining of %s\n", flow_graph_-> | 921 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 888 parsed_function().function().ToFullyQualifiedCString()); | 922 parsed_function().function().ToFullyQualifiedCString()); |
| 889 FlowGraphPrinter printer(*flow_graph_); | 923 FlowGraphPrinter printer(*flow_graph_); |
| 890 printer.PrintBlocks(); | 924 printer.PrintBlocks(); |
| 891 } | 925 } |
| 892 } | 926 } |
| 893 } | 927 } |
| 894 } | 928 } |
| 895 | 929 |
| 896 } // namespace dart | 930 } // namespace dart |
| OLD | NEW |