| 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/block_scheduler.h" | 7 #include "vm/block_scheduler.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" |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 while (env != NULL) { | 80 while (env != NULL) { |
| 81 if (code.raw() == env->code().raw()) { | 81 if (code.raw() == env->code().raw()) { |
| 82 return true; | 82 return true; |
| 83 } | 83 } |
| 84 env = env->outer(); | 84 env = env->outer(); |
| 85 } | 85 } |
| 86 return false; | 86 return false; |
| 87 } | 87 } |
| 88 | 88 |
| 89 | 89 |
| 90 // Helper to create a parameter stub from an actual argument. | |
| 91 static Definition* CreateParameterStub(intptr_t i, | |
| 92 Value* argument, | |
| 93 FlowGraph* graph) { | |
| 94 ConstantInstr* constant = argument->definition()->AsConstant(); | |
| 95 if (constant != NULL) { | |
| 96 return new ConstantInstr(constant->value()); | |
| 97 } else { | |
| 98 return new ParameterInstr(i, graph->graph_entry()); | |
| 99 } | |
| 100 } | |
| 101 | |
| 102 | |
| 103 // Helper to get the default value of a formal parameter. | 90 // Helper to get the default value of a formal parameter. |
| 104 static ConstantInstr* GetDefaultValue(intptr_t i, | 91 static ConstantInstr* GetDefaultValue(intptr_t i, |
| 105 const ParsedFunction& parsed_function) { | 92 const ParsedFunction& parsed_function) { |
| 106 return new ConstantInstr(Object::ZoneHandle( | 93 return new ConstantInstr(Object::ZoneHandle( |
| 107 parsed_function.default_parameter_values().At(i))); | 94 parsed_function.default_parameter_values().At(i))); |
| 108 } | 95 } |
| 109 | 96 |
| 110 | 97 |
| 111 // Pair of an argument name and its value. | 98 // Pair of an argument name and its value. |
| 112 struct NamedArgument { | 99 struct NamedArgument { |
| (...skipping 326 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 | 426 |
| 440 private: | 427 private: |
| 441 bool CheckInlinedDuplicate(const Function& target); | 428 bool CheckInlinedDuplicate(const Function& target); |
| 442 bool CheckNonInlinedDuplicate(const Function& target); | 429 bool CheckNonInlinedDuplicate(const Function& target); |
| 443 | 430 |
| 444 bool TryInliningPoly(intptr_t receiver_cid, const Function& target); | 431 bool TryInliningPoly(intptr_t receiver_cid, const Function& target); |
| 445 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); | 432 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); |
| 446 | 433 |
| 447 TargetEntryInstr* BuildDecisionGraph(); | 434 TargetEntryInstr* BuildDecisionGraph(); |
| 448 | 435 |
| 436 Isolate* isolate() const; |
| 437 |
| 449 CallSiteInliner* const owner_; | 438 CallSiteInliner* const owner_; |
| 450 PolymorphicInstanceCallInstr* const call_; | 439 PolymorphicInstanceCallInstr* const call_; |
| 451 const intptr_t num_variants_; | 440 const intptr_t num_variants_; |
| 452 GrowableArray<CidTarget> variants_; | 441 GrowableArray<CidTarget> variants_; |
| 453 | 442 |
| 454 GrowableArray<CidTarget> inlined_variants_; | 443 GrowableArray<CidTarget> inlined_variants_; |
| 455 GrowableArray<CidTarget> non_inlined_variants_; | 444 GrowableArray<CidTarget> non_inlined_variants_; |
| 456 GrowableArray<BlockEntryInstr*> inlined_entries_; | 445 GrowableArray<BlockEntryInstr*> inlined_entries_; |
| 457 InlineExitCollector* exit_collector_; | 446 InlineExitCollector* exit_collector_; |
| 458 | 447 |
| 459 const Function& caller_function_; | 448 const Function& caller_function_; |
| 460 }; | 449 }; |
| 461 | 450 |
| 462 | 451 |
| 463 class CallSiteInliner : public ValueObject { | 452 class CallSiteInliner : public ValueObject { |
| 464 public: | 453 public: |
| 465 explicit CallSiteInliner(FlowGraph* flow_graph) | 454 explicit CallSiteInliner(FlowGraph* flow_graph) |
| 466 : caller_graph_(flow_graph), | 455 : caller_graph_(flow_graph), |
| 467 inlined_(false), | 456 inlined_(false), |
| 468 initial_size_(flow_graph->InstructionCount()), | 457 initial_size_(flow_graph->InstructionCount()), |
| 469 inlined_size_(0), | 458 inlined_size_(0), |
| 470 inlining_depth_(1), | 459 inlining_depth_(1), |
| 471 collected_call_sites_(NULL), | 460 collected_call_sites_(NULL), |
| 472 inlining_call_sites_(NULL), | 461 inlining_call_sites_(NULL), |
| 473 function_cache_(), | 462 function_cache_(), |
| 474 inlined_info_() { } | 463 inlined_info_() { } |
| 475 | 464 |
| 476 FlowGraph* caller_graph() const { return caller_graph_; } | 465 FlowGraph* caller_graph() const { return caller_graph_; } |
| 477 | 466 |
| 467 Isolate* isolate() const { return caller_graph_->isolate(); } |
| 468 |
| 478 // Inlining heuristics based on Cooper et al. 2008. | 469 // Inlining heuristics based on Cooper et al. 2008. |
| 479 bool ShouldWeInline(const Function& callee, | 470 bool ShouldWeInline(const Function& callee, |
| 480 intptr_t instr_count, | 471 intptr_t instr_count, |
| 481 intptr_t call_site_count, | 472 intptr_t call_site_count, |
| 482 intptr_t const_arg_count) { | 473 intptr_t const_arg_count) { |
| 483 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 474 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
| 484 // Prevent methods becoming humongous and thus slow to compile. | 475 // Prevent methods becoming humongous and thus slow to compile. |
| 485 return false; | 476 return false; |
| 486 } | 477 } |
| 487 if (instr_count > FLAG_inlining_callee_size_threshold) { | 478 if (instr_count > FLAG_inlining_callee_size_threshold) { |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 547 inlining_call_sites_ = NULL; | 538 inlining_call_sites_ = NULL; |
| 548 } | 539 } |
| 549 | 540 |
| 550 bool inlined() const { return inlined_; } | 541 bool inlined() const { return inlined_; } |
| 551 | 542 |
| 552 double GrowthFactor() const { | 543 double GrowthFactor() const { |
| 553 return static_cast<double>(inlined_size_) / | 544 return static_cast<double>(inlined_size_) / |
| 554 static_cast<double>(initial_size_); | 545 static_cast<double>(initial_size_); |
| 555 } | 546 } |
| 556 | 547 |
| 548 // Helper to create a parameter stub from an actual argument. |
| 549 Definition* CreateParameterStub(intptr_t i, |
| 550 Value* argument, |
| 551 FlowGraph* graph) { |
| 552 ConstantInstr* constant = argument->definition()->AsConstant(); |
| 553 if (constant != NULL) { |
| 554 return new(isolate()) ConstantInstr(constant->value()); |
| 555 } else { |
| 556 return new(isolate()) ParameterInstr(i, graph->graph_entry()); |
| 557 } |
| 558 } |
| 559 |
| 557 bool TryInlining(const Function& function, | 560 bool TryInlining(const Function& function, |
| 558 const Array& argument_names, | 561 const Array& argument_names, |
| 559 InlinedCallData* call_data) { | 562 InlinedCallData* call_data) { |
| 560 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 563 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", |
| 561 function.ToCString(), | 564 function.ToCString(), |
| 562 function.deoptimization_counter())); | 565 function.deoptimization_counter())); |
| 563 | 566 |
| 564 // TODO(fschneider): Enable inlining inside try-blocks. | 567 // TODO(fschneider): Enable inlining inside try-blocks. |
| 565 if (call_data->call->GetBlock()->try_index() != | 568 if (call_data->call->GetBlock()->try_index() != |
| 566 CatchClauseNode::kInvalidTryIndex) { | 569 CatchClauseNode::kInvalidTryIndex) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 612 // Abort if this is a recursive occurrence. | 615 // Abort if this is a recursive occurrence. |
| 613 Definition* call = call_data->call; | 616 Definition* call = call_data->call; |
| 614 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { | 617 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { |
| 615 function.set_is_inlinable(false); | 618 function.set_is_inlinable(false); |
| 616 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 619 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 617 PRINT_INLINING_TREE("Recursive function", | 620 PRINT_INLINING_TREE("Recursive function", |
| 618 &call_data->caller, &function, call_data->call); | 621 &call_data->caller, &function, call_data->call); |
| 619 return false; | 622 return false; |
| 620 } | 623 } |
| 621 | 624 |
| 622 Isolate* isolate = Isolate::Current(); | |
| 623 // Save and clear deopt id. | 625 // Save and clear deopt id. |
| 624 const intptr_t prev_deopt_id = isolate->deopt_id(); | 626 const intptr_t prev_deopt_id = isolate()->deopt_id(); |
| 625 isolate->set_deopt_id(0); | 627 isolate()->set_deopt_id(0); |
| 626 // Install bailout jump. | 628 // Install bailout jump. |
| 627 LongJumpScope jump; | 629 LongJumpScope jump; |
| 628 if (setjmp(*jump.Set()) == 0) { | 630 if (setjmp(*jump.Set()) == 0) { |
| 629 // Parse the callee function. | 631 // Parse the callee function. |
| 630 bool in_cache; | 632 bool in_cache; |
| 631 ParsedFunction* parsed_function; | 633 ParsedFunction* parsed_function; |
| 632 { | 634 { |
| 633 TimerScope timer(FLAG_compiler_stats, | 635 TimerScope timer(FLAG_compiler_stats, |
| 634 &CompilerStats::graphinliner_parse_timer, | 636 &CompilerStats::graphinliner_parse_timer, |
| 635 isolate); | 637 isolate()); |
| 636 parsed_function = GetParsedFunction(function, &in_cache); | 638 parsed_function = GetParsedFunction(function, &in_cache); |
| 637 } | 639 } |
| 638 | 640 |
| 639 // Load IC data for the callee. | 641 // Load IC data for the callee. |
| 640 Array& ic_data_array = Array::Handle(); | 642 Array& ic_data_array = Array::Handle(); |
| 641 | 643 |
| 642 // IsInlineable above checked HasCode. Creating a Handle for the code | 644 // IsInlineable above checked HasCode. Creating a Handle for the code |
| 643 // should have kept GC from detaching, but let's assert just to make sure. | 645 // should have kept GC from detaching, but let's assert just to make sure. |
| 644 ASSERT(function.HasCode()); | 646 ASSERT(function.HasCode()); |
| 645 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); | 647 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); |
| 646 | 648 |
| 647 // Build the callee graph. | 649 // Build the callee graph. |
| 648 InlineExitCollector* exit_collector = | 650 InlineExitCollector* exit_collector = |
| 649 new InlineExitCollector(caller_graph_, call); | 651 new(isolate()) InlineExitCollector(caller_graph_, call); |
| 650 FlowGraphBuilder builder(parsed_function, | 652 FlowGraphBuilder builder(parsed_function, |
| 651 ic_data_array, | 653 ic_data_array, |
| 652 exit_collector, | 654 exit_collector, |
| 653 Isolate::kNoDeoptId, | 655 Isolate::kNoDeoptId, |
| 654 true); | 656 true); |
| 655 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 657 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 656 FlowGraph* callee_graph; | 658 FlowGraph* callee_graph; |
| 657 { | 659 { |
| 658 TimerScope timer(FLAG_compiler_stats, | 660 TimerScope timer(FLAG_compiler_stats, |
| 659 &CompilerStats::graphinliner_build_timer, | 661 &CompilerStats::graphinliner_build_timer, |
| 660 isolate); | 662 isolate()); |
| 661 callee_graph = builder.BuildGraph(); | 663 callee_graph = builder.BuildGraph(); |
| 662 } | 664 } |
| 663 | 665 |
| 664 // The parameter stubs are a copy of the actual arguments providing | 666 // The parameter stubs are a copy of the actual arguments providing |
| 665 // concrete information about the values, for example constant values, | 667 // concrete information about the values, for example constant values, |
| 666 // without linking between the caller and callee graphs. | 668 // without linking between the caller and callee graphs. |
| 667 // TODO(zerny): Put more information in the stubs, eg, type information. | 669 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 668 ZoneGrowableArray<Definition*>* param_stubs = | 670 ZoneGrowableArray<Definition*>* param_stubs = |
| 669 new ZoneGrowableArray<Definition*>(function.NumParameters()); | 671 new(isolate()) ZoneGrowableArray<Definition*>( |
| 672 function.NumParameters()); |
| 670 | 673 |
| 671 // Create a parameter stub for each fixed positional parameter. | 674 // Create a parameter stub for each fixed positional parameter. |
| 672 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 675 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 673 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 676 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 674 } | 677 } |
| 675 | 678 |
| 676 // If the callee has optional parameters, rebuild the argument and stub | 679 // If the callee has optional parameters, rebuild the argument and stub |
| 677 // arrays so that actual arguments are in one-to-one with the formal | 680 // arrays so that actual arguments are in one-to-one with the formal |
| 678 // parameters. | 681 // parameters. |
| 679 if (function.HasOptionalParameters()) { | 682 if (function.HasOptionalParameters()) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 694 // After treating optional parameters the actual/formal count must match. | 697 // After treating optional parameters the actual/formal count must match. |
| 695 ASSERT(arguments->length() == function.NumParameters()); | 698 ASSERT(arguments->length() == function.NumParameters()); |
| 696 ASSERT(param_stubs->length() == callee_graph->parameter_count()); | 699 ASSERT(param_stubs->length() == callee_graph->parameter_count()); |
| 697 | 700 |
| 698 BlockScheduler block_scheduler(callee_graph); | 701 BlockScheduler block_scheduler(callee_graph); |
| 699 block_scheduler.AssignEdgeWeights(); | 702 block_scheduler.AssignEdgeWeights(); |
| 700 | 703 |
| 701 { | 704 { |
| 702 TimerScope timer(FLAG_compiler_stats, | 705 TimerScope timer(FLAG_compiler_stats, |
| 703 &CompilerStats::graphinliner_ssa_timer, | 706 &CompilerStats::graphinliner_ssa_timer, |
| 704 isolate); | 707 isolate()); |
| 705 // Compute SSA on the callee graph, catching bailouts. | 708 // Compute SSA on the callee graph, catching bailouts. |
| 706 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), | 709 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), |
| 707 param_stubs); | 710 param_stubs); |
| 708 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 711 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 709 } | 712 } |
| 710 | 713 |
| 711 { | 714 { |
| 712 TimerScope timer(FLAG_compiler_stats, | 715 TimerScope timer(FLAG_compiler_stats, |
| 713 &CompilerStats::graphinliner_opt_timer, | 716 &CompilerStats::graphinliner_opt_timer, |
| 714 isolate); | 717 isolate()); |
| 715 // TODO(zerny): Do more optimization passes on the callee graph. | 718 // TODO(zerny): Do more optimization passes on the callee graph. |
| 716 FlowGraphOptimizer optimizer(callee_graph); | 719 FlowGraphOptimizer optimizer(callee_graph); |
| 717 optimizer.ApplyICData(); | 720 optimizer.ApplyICData(); |
| 718 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 721 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 719 | 722 |
| 720 // Optimize (a << b) & c patterns, merge instructions. Must occur before | 723 // Optimize (a << b) & c patterns, merge instructions. Must occur before |
| 721 // 'SelectRepresentations' which inserts conversion nodes. | 724 // 'SelectRepresentations' which inserts conversion nodes. |
| 722 optimizer.TryOptimizePatterns(); | 725 optimizer.TryOptimizePatterns(); |
| 723 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 726 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
| 724 } | 727 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 746 function.set_optimized_call_site_count(call_site_count); | 749 function.set_optimized_call_site_count(call_site_count); |
| 747 | 750 |
| 748 // Use heuristics do decide if this call should be inlined. | 751 // Use heuristics do decide if this call should be inlined. |
| 749 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { | 752 if (!ShouldWeInline(function, size, call_site_count, constants_count)) { |
| 750 // If size is larger than all thresholds, don't consider it again. | 753 // If size is larger than all thresholds, don't consider it again. |
| 751 if ((size > FLAG_inlining_size_threshold) && | 754 if ((size > FLAG_inlining_size_threshold) && |
| 752 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && | 755 (call_site_count > FLAG_inlining_callee_call_sites_threshold) && |
| 753 (size > FLAG_inlining_constant_arguments_size_threshold)) { | 756 (size > FLAG_inlining_constant_arguments_size_threshold)) { |
| 754 function.set_is_inlinable(false); | 757 function.set_is_inlinable(false); |
| 755 } | 758 } |
| 756 isolate->set_deopt_id(prev_deopt_id); | 759 isolate()->set_deopt_id(prev_deopt_id); |
| 757 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 760 TRACE_INLINING(OS::Print(" Bailout: heuristics with " |
| 758 "code size: %" Pd ", " | 761 "code size: %" Pd ", " |
| 759 "call sites: %" Pd ", " | 762 "call sites: %" Pd ", " |
| 760 "const args: %" Pd "\n", | 763 "const args: %" Pd "\n", |
| 761 size, | 764 size, |
| 762 call_site_count, | 765 call_site_count, |
| 763 constants_count)); | 766 constants_count)); |
| 764 PRINT_INLINING_TREE("Heuristic fail", | 767 PRINT_INLINING_TREE("Heuristic fail", |
| 765 &call_data->caller, &function, call_data->call); | 768 &call_data->caller, &function, call_data->call); |
| 766 return false; | 769 return false; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 780 } | 783 } |
| 781 | 784 |
| 782 // Add the function to the cache. | 785 // Add the function to the cache. |
| 783 if (!in_cache) { | 786 if (!in_cache) { |
| 784 function_cache_.Add(parsed_function); | 787 function_cache_.Add(parsed_function); |
| 785 } | 788 } |
| 786 | 789 |
| 787 // Build succeeded so we restore the bailout jump. | 790 // Build succeeded so we restore the bailout jump. |
| 788 inlined_ = true; | 791 inlined_ = true; |
| 789 inlined_size_ += size; | 792 inlined_size_ += size; |
| 790 isolate->set_deopt_id(prev_deopt_id); | 793 isolate()->set_deopt_id(prev_deopt_id); |
| 791 | 794 |
| 792 call_data->callee_graph = callee_graph; | 795 call_data->callee_graph = callee_graph; |
| 793 call_data->parameter_stubs = param_stubs; | 796 call_data->parameter_stubs = param_stubs; |
| 794 call_data->exit_collector = exit_collector; | 797 call_data->exit_collector = exit_collector; |
| 795 | 798 |
| 796 // When inlined, we add the guarded fields of the callee to the caller's | 799 // When inlined, we add the guarded fields of the callee to the caller's |
| 797 // list of guarded fields. | 800 // list of guarded fields. |
| 798 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { | 801 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { |
| 799 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), | 802 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), |
| 800 (*callee_graph->guarded_fields())[i]); | 803 (*callee_graph->guarded_fields())[i]); |
| 801 } | 804 } |
| 802 | 805 |
| 803 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 806 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
| 804 // disconnected from its function during the rest of compilation. | 807 // disconnected from its function during the rest of compilation. |
| 805 Code::ZoneHandle(unoptimized_code.raw()); | 808 Code::ZoneHandle(unoptimized_code.raw()); |
| 806 TRACE_INLINING(OS::Print(" Success\n")); | 809 TRACE_INLINING(OS::Print(" Success\n")); |
| 807 PRINT_INLINING_TREE(NULL, | 810 PRINT_INLINING_TREE(NULL, |
| 808 &call_data->caller, &function, call); | 811 &call_data->caller, &function, call); |
| 809 return true; | 812 return true; |
| 810 } else { | 813 } else { |
| 811 Error& error = Error::Handle(); | 814 Error& error = Error::Handle(); |
| 812 error = isolate->object_store()->sticky_error(); | 815 error = isolate()->object_store()->sticky_error(); |
| 813 isolate->object_store()->clear_sticky_error(); | 816 isolate()->object_store()->clear_sticky_error(); |
| 814 isolate->set_deopt_id(prev_deopt_id); | 817 isolate()->set_deopt_id(prev_deopt_id); |
| 815 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 818 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 816 PRINT_INLINING_TREE("Bailout", | 819 PRINT_INLINING_TREE("Bailout", |
| 817 &call_data->caller, &function, call); | 820 &call_data->caller, &function, call); |
| 818 return false; | 821 return false; |
| 819 } | 822 } |
| 820 } | 823 } |
| 821 | 824 |
| 822 void PrintInlinedInfo(const Function& top) { | 825 void PrintInlinedInfo(const Function& top) { |
| 823 if (inlined_info_.length() > 0) { | 826 if (inlined_info_.length() > 0) { |
| 824 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", | 827 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 942 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 945 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| 943 // TODO(zerny): Use a hash map for the cache. | 946 // TODO(zerny): Use a hash map for the cache. |
| 944 for (intptr_t i = 0; i < function_cache_.length(); ++i) { | 947 for (intptr_t i = 0; i < function_cache_.length(); ++i) { |
| 945 ParsedFunction* parsed_function = function_cache_[i]; | 948 ParsedFunction* parsed_function = function_cache_[i]; |
| 946 if (parsed_function->function().raw() == function.raw()) { | 949 if (parsed_function->function().raw() == function.raw()) { |
| 947 *in_cache = true; | 950 *in_cache = true; |
| 948 return parsed_function; | 951 return parsed_function; |
| 949 } | 952 } |
| 950 } | 953 } |
| 951 *in_cache = false; | 954 *in_cache = false; |
| 952 ParsedFunction* parsed_function = new ParsedFunction(function); | 955 ParsedFunction* parsed_function = new(isolate()) ParsedFunction(function); |
| 953 Parser::ParseFunction(parsed_function); | 956 Parser::ParseFunction(parsed_function); |
| 954 parsed_function->AllocateVariables(); | 957 parsed_function->AllocateVariables(); |
| 955 return parsed_function; | 958 return parsed_function; |
| 956 } | 959 } |
| 957 | 960 |
| 958 // Include special handling for List. factory: inlining it is not helpful | 961 // Include special handling for List. factory: inlining it is not helpful |
| 959 // if the incoming argument is a non-constant value. | 962 // if the incoming argument is a non-constant value. |
| 960 // TODO(srdjan): Fix inlining of List. factory. | 963 // TODO(srdjan): Fix inlining of List. factory. |
| 961 void InlineStaticCalls() { | 964 void InlineStaticCalls() { |
| 962 const GrowableArray<CallSites::StaticCallInfo>& call_info = | 965 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1096 } | 1099 } |
| 1097 ASSERT(function.NumOptionalPositionalParameters() == | 1100 ASSERT(function.NumOptionalPositionalParameters() == |
| 1098 (param_count - fixed_param_count)); | 1101 (param_count - fixed_param_count)); |
| 1099 // For each optional positional parameter without an actual, add its | 1102 // For each optional positional parameter without an actual, add its |
| 1100 // default value. | 1103 // default value. |
| 1101 for (intptr_t i = arg_count; i < param_count; ++i) { | 1104 for (intptr_t i = arg_count; i < param_count; ++i) { |
| 1102 const Object& object = | 1105 const Object& object = |
| 1103 Object::ZoneHandle( | 1106 Object::ZoneHandle( |
| 1104 parsed_function.default_parameter_values().At( | 1107 parsed_function.default_parameter_values().At( |
| 1105 i - fixed_param_count)); | 1108 i - fixed_param_count)); |
| 1106 ConstantInstr* constant = new ConstantInstr(object); | 1109 ConstantInstr* constant = new(isolate()) ConstantInstr(object); |
| 1107 arguments->Add(NULL); | 1110 arguments->Add(NULL); |
| 1108 param_stubs->Add(constant); | 1111 param_stubs->Add(constant); |
| 1109 } | 1112 } |
| 1110 return true; | 1113 return true; |
| 1111 } | 1114 } |
| 1112 | 1115 |
| 1113 ASSERT(function.HasOptionalNamedParameters()); | 1116 ASSERT(function.HasOptionalNamedParameters()); |
| 1114 | 1117 |
| 1115 // Passed arguments must match fixed parameters plus named arguments. | 1118 // Passed arguments must match fixed parameters plus named arguments. |
| 1116 intptr_t argument_names_count = | 1119 intptr_t argument_names_count = |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1181 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1184 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
| 1182 PolymorphicInstanceCallInstr* call, | 1185 PolymorphicInstanceCallInstr* call, |
| 1183 const Function& caller_function) | 1186 const Function& caller_function) |
| 1184 : owner_(owner), | 1187 : owner_(owner), |
| 1185 call_(call), | 1188 call_(call), |
| 1186 num_variants_(call->ic_data().NumberOfChecks()), | 1189 num_variants_(call->ic_data().NumberOfChecks()), |
| 1187 variants_(num_variants_), | 1190 variants_(num_variants_), |
| 1188 inlined_variants_(num_variants_), | 1191 inlined_variants_(num_variants_), |
| 1189 non_inlined_variants_(num_variants_), | 1192 non_inlined_variants_(num_variants_), |
| 1190 inlined_entries_(num_variants_), | 1193 inlined_entries_(num_variants_), |
| 1191 exit_collector_(new InlineExitCollector(owner->caller_graph(), call)), | 1194 exit_collector_(new(isolate()) |
| 1195 InlineExitCollector(owner->caller_graph(), call)), |
| 1192 caller_function_(caller_function) { | 1196 caller_function_(caller_function) { |
| 1193 } | 1197 } |
| 1194 | 1198 |
| 1195 | 1199 |
| 1200 Isolate* PolymorphicInliner::isolate() const { |
| 1201 return owner_->caller_graph()->isolate(); |
| 1202 } |
| 1203 |
| 1204 |
| 1196 // Inlined bodies are shared if two different class ids have the same | 1205 // Inlined bodies are shared if two different class ids have the same |
| 1197 // inlined target. This sharing is represented by using three different | 1206 // inlined target. This sharing is represented by using three different |
| 1198 // types of entries in the inlined_entries_ array: | 1207 // types of entries in the inlined_entries_ array: |
| 1199 // | 1208 // |
| 1200 // * GraphEntry: the inlined body is not shared. | 1209 // * GraphEntry: the inlined body is not shared. |
| 1201 // | 1210 // |
| 1202 // * TargetEntry: the inlined body is shared and this is the first variant. | 1211 // * TargetEntry: the inlined body is shared and this is the first variant. |
| 1203 // | 1212 // |
| 1204 // * JoinEntry: the inlined body is shared and this is a subsequent variant. | 1213 // * JoinEntry: the inlined body is shared and this is a subsequent variant. |
| 1205 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { | 1214 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { |
| 1206 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1215 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
| 1207 if ((target.raw() == inlined_variants_[i].target->raw()) && | 1216 if ((target.raw() == inlined_variants_[i].target->raw()) && |
| 1208 !MethodRecognizer::PolymorphicTarget(target)) { | 1217 !MethodRecognizer::PolymorphicTarget(target)) { |
| 1209 // The call target is shared with a previous inlined variant. Share | 1218 // The call target is shared with a previous inlined variant. Share |
| 1210 // the graph. This requires a join block at the entry, and edge-split | 1219 // the graph. This requires a join block at the entry, and edge-split |
| 1211 // form requires a target for each branch. | 1220 // form requires a target for each branch. |
| 1212 // | 1221 // |
| 1213 // Represent the sharing by recording a fresh target for the first | 1222 // Represent the sharing by recording a fresh target for the first |
| 1214 // variant and the shared join for all later variants. | 1223 // variant and the shared join for all later variants. |
| 1215 if (inlined_entries_[i]->IsGraphEntry()) { | 1224 if (inlined_entries_[i]->IsGraphEntry()) { |
| 1216 // Convert the old target entry to a new join entry. | 1225 // Convert the old target entry to a new join entry. |
| 1217 TargetEntryInstr* old_target = | 1226 TargetEntryInstr* old_target = |
| 1218 inlined_entries_[i]->AsGraphEntry()->normal_entry(); | 1227 inlined_entries_[i]->AsGraphEntry()->normal_entry(); |
| 1219 // Unuse all inputs in the the old graph entry since it is not part of | 1228 // Unuse all inputs in the the old graph entry since it is not part of |
| 1220 // the graph anymore. A new target be created instead. | 1229 // the graph anymore. A new target be created instead. |
| 1221 inlined_entries_[i]->AsGraphEntry()->UnuseAllInputs(); | 1230 inlined_entries_[i]->AsGraphEntry()->UnuseAllInputs(); |
| 1222 | 1231 |
| 1223 JoinEntryInstr* new_join = BranchSimplifier::ToJoinEntry(old_target); | 1232 JoinEntryInstr* new_join = |
| 1233 BranchSimplifier::ToJoinEntry(isolate(), old_target); |
| 1224 old_target->ReplaceAsPredecessorWith(new_join); | 1234 old_target->ReplaceAsPredecessorWith(new_join); |
| 1225 for (intptr_t j = 0; j < old_target->dominated_blocks().length(); ++j) { | 1235 for (intptr_t j = 0; j < old_target->dominated_blocks().length(); ++j) { |
| 1226 BlockEntryInstr* block = old_target->dominated_blocks()[j]; | 1236 BlockEntryInstr* block = old_target->dominated_blocks()[j]; |
| 1227 new_join->AddDominatedBlock(block); | 1237 new_join->AddDominatedBlock(block); |
| 1228 } | 1238 } |
| 1229 // Create a new target with the join as unconditional successor. | 1239 // Create a new target with the join as unconditional successor. |
| 1230 TargetEntryInstr* new_target = | 1240 TargetEntryInstr* new_target = |
| 1231 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1241 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), |
| 1232 old_target->try_index()); | 1242 old_target->try_index()); |
| 1233 new_target->InheritDeoptTarget(new_join); | 1243 new_target->InheritDeoptTarget(isolate(), new_join); |
| 1234 GotoInstr* new_goto = new GotoInstr(new_join); | 1244 GotoInstr* new_goto = new(isolate()) GotoInstr(new_join); |
| 1235 new_goto->InheritDeoptTarget(new_join); | 1245 new_goto->InheritDeoptTarget(isolate(), new_join); |
| 1236 new_target->LinkTo(new_goto); | 1246 new_target->LinkTo(new_goto); |
| 1237 new_target->set_last_instruction(new_goto); | 1247 new_target->set_last_instruction(new_goto); |
| 1238 new_join->predecessors_.Add(new_target); | 1248 new_join->predecessors_.Add(new_target); |
| 1239 | 1249 |
| 1240 // Record the new target for the first variant. | 1250 // Record the new target for the first variant. |
| 1241 inlined_entries_[i] = new_target; | 1251 inlined_entries_[i] = new_target; |
| 1242 } | 1252 } |
| 1243 ASSERT(inlined_entries_[i]->IsTargetEntry()); | 1253 ASSERT(inlined_entries_[i]->IsTargetEntry()); |
| 1244 // Record the shared join for this variant. | 1254 // Record the shared join for this variant. |
| 1245 BlockEntryInstr* join = | 1255 BlockEntryInstr* join = |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1289 FlowGraph* callee_graph = call_data.callee_graph; | 1299 FlowGraph* callee_graph = call_data.callee_graph; |
| 1290 call_data.exit_collector->PrepareGraphs(callee_graph); | 1300 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1291 inlined_entries_.Add(callee_graph->graph_entry()); | 1301 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1292 exit_collector_->Union(call_data.exit_collector); | 1302 exit_collector_->Union(call_data.exit_collector); |
| 1293 | 1303 |
| 1294 // Replace parameter stubs and constants. Replace the receiver argument | 1304 // Replace parameter stubs and constants. Replace the receiver argument |
| 1295 // with a redefinition to prevent code from the inlined body from being | 1305 // with a redefinition to prevent code from the inlined body from being |
| 1296 // hoisted above the inlined entry. | 1306 // hoisted above the inlined entry. |
| 1297 ASSERT(arguments.length() > 0); | 1307 ASSERT(arguments.length() > 0); |
| 1298 Value* actual = arguments[0]; | 1308 Value* actual = arguments[0]; |
| 1299 RedefinitionInstr* redefinition = new RedefinitionInstr(actual->Copy()); | 1309 RedefinitionInstr* redefinition = new(isolate()) |
| 1310 RedefinitionInstr(actual->Copy(isolate())); |
| 1300 redefinition->set_ssa_temp_index( | 1311 redefinition->set_ssa_temp_index( |
| 1301 owner_->caller_graph()->alloc_ssa_temp_index()); | 1312 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1302 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | 1313 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); |
| 1303 Definition* stub = (*call_data.parameter_stubs)[0]; | 1314 Definition* stub = (*call_data.parameter_stubs)[0]; |
| 1304 stub->ReplaceUsesWith(redefinition); | 1315 stub->ReplaceUsesWith(redefinition); |
| 1305 | 1316 |
| 1306 for (intptr_t i = 1; i < arguments.length(); ++i) { | 1317 for (intptr_t i = 1; i < arguments.length(); ++i) { |
| 1307 actual = arguments[i]; | 1318 actual = arguments[i]; |
| 1308 if (actual != NULL) { | 1319 if (actual != NULL) { |
| 1309 stub = (*call_data.parameter_stubs)[i]; | 1320 stub = (*call_data.parameter_stubs)[i]; |
| (...skipping 27 matching lines...) Expand all Loading... |
| 1337 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, | 1348 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, |
| 1338 const Function& target) { | 1349 const Function& target) { |
| 1339 FlowGraphOptimizer optimizer(owner_->caller_graph()); | 1350 FlowGraphOptimizer optimizer(owner_->caller_graph()); |
| 1340 TargetEntryInstr* entry; | 1351 TargetEntryInstr* entry; |
| 1341 Definition* last; | 1352 Definition* last; |
| 1342 // Replace the receiver argument with a redefinition to prevent code from | 1353 // Replace the receiver argument with a redefinition to prevent code from |
| 1343 // the inlined body from being hoisted above the inlined entry. | 1354 // the inlined body from being hoisted above the inlined entry. |
| 1344 GrowableArray<Definition*> arguments(call_->ArgumentCount()); | 1355 GrowableArray<Definition*> arguments(call_->ArgumentCount()); |
| 1345 Definition* receiver = call_->ArgumentAt(0); | 1356 Definition* receiver = call_->ArgumentAt(0); |
| 1346 RedefinitionInstr* redefinition = | 1357 RedefinitionInstr* redefinition = |
| 1347 new RedefinitionInstr(new Value(receiver)); | 1358 new(isolate()) RedefinitionInstr(new(isolate()) Value(receiver)); |
| 1348 redefinition->set_ssa_temp_index( | 1359 redefinition->set_ssa_temp_index( |
| 1349 owner_->caller_graph()->alloc_ssa_temp_index()); | 1360 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1350 if (optimizer.TryInlineRecognizedMethod(receiver_cid, | 1361 if (optimizer.TryInlineRecognizedMethod(receiver_cid, |
| 1351 target, | 1362 target, |
| 1352 call_, | 1363 call_, |
| 1353 redefinition, | 1364 redefinition, |
| 1354 call_->instance_call()->token_pos(), | 1365 call_->instance_call()->token_pos(), |
| 1355 *call_->instance_call()->ic_data(), | 1366 *call_->instance_call()->ic_data(), |
| 1356 &entry, &last)) { | 1367 &entry, &last)) { |
| 1357 // Create a graph fragment. | 1368 // Create a graph fragment. |
| 1358 redefinition->InsertAfter(entry); | 1369 redefinition->InsertAfter(entry); |
| 1359 InlineExitCollector* exit_collector = | 1370 InlineExitCollector* exit_collector = |
| 1360 new InlineExitCollector(owner_->caller_graph(), call_); | 1371 new(isolate()) InlineExitCollector(owner_->caller_graph(), call_); |
| 1361 | 1372 |
| 1362 ReturnInstr* result = | 1373 ReturnInstr* result = |
| 1363 new ReturnInstr(call_->instance_call()->token_pos(), | 1374 new(isolate()) ReturnInstr(call_->instance_call()->token_pos(), |
| 1364 new Value(last)); | 1375 new(isolate()) Value(last)); |
| 1365 owner_->caller_graph()->AppendTo( | 1376 owner_->caller_graph()->AppendTo( |
| 1366 last, | 1377 last, |
| 1367 result, | 1378 result, |
| 1368 call_->env(), // Return can become deoptimization target. | 1379 call_->env(), // Return can become deoptimization target. |
| 1369 FlowGraph::kEffect); | 1380 FlowGraph::kEffect); |
| 1370 entry->set_last_instruction(result); | 1381 entry->set_last_instruction(result); |
| 1371 exit_collector->AddExit(result); | 1382 exit_collector->AddExit(result); |
| 1372 GraphEntryInstr* graph_entry = | 1383 GraphEntryInstr* graph_entry = |
| 1373 new GraphEntryInstr(NULL, // No parsed function. | 1384 new(isolate()) GraphEntryInstr(NULL, // No parsed function. |
| 1374 entry, | 1385 entry, |
| 1375 Isolate::kNoDeoptId); // No OSR id. | 1386 Isolate::kNoDeoptId); // No OSR id. |
| 1376 // Update polymorphic inliner state. | 1387 // Update polymorphic inliner state. |
| 1377 inlined_entries_.Add(graph_entry); | 1388 inlined_entries_.Add(graph_entry); |
| 1378 exit_collector_->Union(exit_collector); | 1389 exit_collector_->Union(exit_collector); |
| 1379 return true; | 1390 return true; |
| 1380 } | 1391 } |
| 1381 return false; | 1392 return false; |
| 1382 } | 1393 } |
| 1383 | 1394 |
| 1384 | 1395 |
| 1385 // Build a DAG to dispatch to the inlined function bodies. Load the class | 1396 // Build a DAG to dispatch to the inlined function bodies. Load the class |
| 1386 // id of the receiver and make explicit comparisons for each inlined body, | 1397 // id of the receiver and make explicit comparisons for each inlined body, |
| 1387 // in frequency order. If all variants are inlined, the entry to the last | 1398 // in frequency order. If all variants are inlined, the entry to the last |
| 1388 // inlined body is guarded by a CheckClassId instruction which can deopt. | 1399 // inlined body is guarded by a CheckClassId instruction which can deopt. |
| 1389 // If not all variants are inlined, we add a PolymorphicInstanceCall | 1400 // If not all variants are inlined, we add a PolymorphicInstanceCall |
| 1390 // instruction to handle the non-inlined variants. | 1401 // instruction to handle the non-inlined variants. |
| 1391 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { | 1402 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
| 1392 // Start with a fresh target entry. | 1403 // Start with a fresh target entry. |
| 1393 TargetEntryInstr* entry = | 1404 TargetEntryInstr* entry = |
| 1394 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1405 new(isolate()) TargetEntryInstr( |
| 1395 call_->GetBlock()->try_index()); | 1406 owner_->caller_graph()->allocate_block_id(), |
| 1396 entry->InheritDeoptTarget(call_); | 1407 call_->GetBlock()->try_index()); |
| 1408 entry->InheritDeoptTarget(isolate(), call_); |
| 1397 | 1409 |
| 1398 // This function uses a cursor (a pointer to the 'current' instruction) to | 1410 // This function uses a cursor (a pointer to the 'current' instruction) to |
| 1399 // build the graph. The next instruction will be inserted after the | 1411 // build the graph. The next instruction will be inserted after the |
| 1400 // cursor. | 1412 // cursor. |
| 1401 TargetEntryInstr* current_block = entry; | 1413 TargetEntryInstr* current_block = entry; |
| 1402 Instruction* cursor = entry; | 1414 Instruction* cursor = entry; |
| 1403 | 1415 |
| 1404 Definition* receiver = call_->ArgumentAt(0); | 1416 Definition* receiver = call_->ArgumentAt(0); |
| 1405 // There are at least two variants including non-inlined ones, so we have | 1417 // There are at least two variants including non-inlined ones, so we have |
| 1406 // at least one branch on the class id. | 1418 // at least one branch on the class id. |
| 1407 LoadClassIdInstr* load_cid = new LoadClassIdInstr(new Value(receiver)); | 1419 LoadClassIdInstr* load_cid = |
| 1420 new(isolate()) LoadClassIdInstr(new(isolate()) Value(receiver)); |
| 1408 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); | 1421 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1409 cursor = AppendInstruction(cursor, load_cid); | 1422 cursor = AppendInstruction(cursor, load_cid); |
| 1410 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1423 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
| 1411 // 1. Guard the body with a class id check. | 1424 // 1. Guard the body with a class id check. |
| 1412 if ((i == (inlined_variants_.length() - 1)) && | 1425 if ((i == (inlined_variants_.length() - 1)) && |
| 1413 non_inlined_variants_.is_empty()) { | 1426 non_inlined_variants_.is_empty()) { |
| 1414 // If it is the last variant use a check class or check smi | 1427 // If it is the last variant use a check class or check smi |
| 1415 // instruction which can deoptimize, followed unconditionally by the | 1428 // instruction which can deoptimize, followed unconditionally by the |
| 1416 // body. Check a redefinition of the receiver, to prevent the check | 1429 // body. Check a redefinition of the receiver, to prevent the check |
| 1417 // from being hoisted. | 1430 // from being hoisted. |
| 1418 RedefinitionInstr* redefinition = | 1431 RedefinitionInstr* redefinition = |
| 1419 new RedefinitionInstr(new Value(receiver)); | 1432 new(isolate()) RedefinitionInstr(new(isolate()) Value(receiver)); |
| 1420 redefinition->set_ssa_temp_index( | 1433 redefinition->set_ssa_temp_index( |
| 1421 owner_->caller_graph()->alloc_ssa_temp_index()); | 1434 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1422 cursor = AppendInstruction(cursor, redefinition); | 1435 cursor = AppendInstruction(cursor, redefinition); |
| 1423 if (inlined_variants_[i].cid == kSmiCid) { | 1436 if (inlined_variants_[i].cid == kSmiCid) { |
| 1424 CheckSmiInstr* check_smi = | 1437 CheckSmiInstr* check_smi = |
| 1425 new CheckSmiInstr(new Value(redefinition), | 1438 new CheckSmiInstr(new Value(redefinition), |
| 1426 call_->deopt_id(), | 1439 call_->deopt_id(), |
| 1427 call_->token_pos()); | 1440 call_->token_pos()); |
| 1428 check_smi->InheritDeoptTarget(call_); | 1441 check_smi->InheritDeoptTarget(isolate(), call_); |
| 1429 cursor = AppendInstruction(cursor, check_smi); | 1442 cursor = AppendInstruction(cursor, check_smi); |
| 1430 } else { | 1443 } else { |
| 1431 const ICData& old_checks = call_->ic_data(); | 1444 const ICData& old_checks = call_->ic_data(); |
| 1432 const ICData& new_checks = ICData::ZoneHandle( | 1445 const ICData& new_checks = ICData::ZoneHandle( |
| 1433 ICData::New(Function::Handle(old_checks.owner()), | 1446 ICData::New(Function::Handle(old_checks.owner()), |
| 1434 String::Handle(old_checks.target_name()), | 1447 String::Handle(old_checks.target_name()), |
| 1435 Array::Handle(old_checks.arguments_descriptor()), | 1448 Array::Handle(old_checks.arguments_descriptor()), |
| 1436 old_checks.deopt_id(), | 1449 old_checks.deopt_id(), |
| 1437 1)); // Number of args tested. | 1450 1)); // Number of args tested. |
| 1438 new_checks.AddReceiverCheck(inlined_variants_[i].cid, | 1451 new_checks.AddReceiverCheck(inlined_variants_[i].cid, |
| 1439 *inlined_variants_[i].target); | 1452 *inlined_variants_[i].target); |
| 1440 CheckClassInstr* check_class = | 1453 CheckClassInstr* check_class = |
| 1441 new CheckClassInstr(new Value(redefinition), | 1454 new CheckClassInstr(new Value(redefinition), |
| 1442 call_->deopt_id(), | 1455 call_->deopt_id(), |
| 1443 new_checks, | 1456 new_checks, |
| 1444 call_->token_pos()); | 1457 call_->token_pos()); |
| 1445 check_class->InheritDeoptTarget(call_); | 1458 check_class->InheritDeoptTarget(isolate(), call_); |
| 1446 cursor = AppendInstruction(cursor, check_class); | 1459 cursor = AppendInstruction(cursor, check_class); |
| 1447 } | 1460 } |
| 1448 // The next instruction is the first instruction of the inlined body. | 1461 // The next instruction is the first instruction of the inlined body. |
| 1449 // Handle the two possible cases (unshared and shared subsequent | 1462 // Handle the two possible cases (unshared and shared subsequent |
| 1450 // predecessors) separately. | 1463 // predecessors) separately. |
| 1451 BlockEntryInstr* callee_entry = inlined_entries_[i]; | 1464 BlockEntryInstr* callee_entry = inlined_entries_[i]; |
| 1452 if (callee_entry->IsGraphEntry()) { | 1465 if (callee_entry->IsGraphEntry()) { |
| 1453 // Unshared. Graft the normal entry on after the check class | 1466 // Unshared. Graft the normal entry on after the check class |
| 1454 // instruction. | 1467 // instruction. |
| 1455 TargetEntryInstr* target = | 1468 TargetEntryInstr* target = |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1468 BlockEntryInstr* block = target->dominated_blocks()[j]; | 1481 BlockEntryInstr* block = target->dominated_blocks()[j]; |
| 1469 current_block->AddDominatedBlock(block); | 1482 current_block->AddDominatedBlock(block); |
| 1470 } | 1483 } |
| 1471 } else if (callee_entry->IsJoinEntry()) { | 1484 } else if (callee_entry->IsJoinEntry()) { |
| 1472 // Shared inlined body and this is a subsequent entry. We have | 1485 // Shared inlined body and this is a subsequent entry. We have |
| 1473 // already constructed a join and set its dominator. Add a jump to | 1486 // already constructed a join and set its dominator. Add a jump to |
| 1474 // the join. | 1487 // the join. |
| 1475 JoinEntryInstr* join = callee_entry->AsJoinEntry(); | 1488 JoinEntryInstr* join = callee_entry->AsJoinEntry(); |
| 1476 ASSERT(join->dominator() != NULL); | 1489 ASSERT(join->dominator() != NULL); |
| 1477 GotoInstr* goto_join = new GotoInstr(join); | 1490 GotoInstr* goto_join = new GotoInstr(join); |
| 1478 goto_join->InheritDeoptTarget(join); | 1491 goto_join->InheritDeoptTarget(isolate(), join); |
| 1479 cursor->LinkTo(goto_join); | 1492 cursor->LinkTo(goto_join); |
| 1480 current_block->set_last_instruction(goto_join); | 1493 current_block->set_last_instruction(goto_join); |
| 1481 } else { | 1494 } else { |
| 1482 // There is no possibility of a TargetEntry (the first entry to a | 1495 // There is no possibility of a TargetEntry (the first entry to a |
| 1483 // shared inlined body) because this is the last inlined entry. | 1496 // shared inlined body) because this is the last inlined entry. |
| 1484 UNREACHABLE(); | 1497 UNREACHABLE(); |
| 1485 } | 1498 } |
| 1486 cursor = NULL; | 1499 cursor = NULL; |
| 1487 } else { | 1500 } else { |
| 1488 // For all variants except the last, use a branch on the loaded class | 1501 // For all variants except the last, use a branch on the loaded class |
| 1489 // id. | 1502 // id. |
| 1490 const Smi& cid = Smi::ZoneHandle(Smi::New(inlined_variants_[i].cid)); | 1503 const Smi& cid = Smi::ZoneHandle(Smi::New(inlined_variants_[i].cid)); |
| 1491 ConstantInstr* cid_constant = new ConstantInstr(cid); | 1504 ConstantInstr* cid_constant = new ConstantInstr(cid); |
| 1492 cid_constant->set_ssa_temp_index( | 1505 cid_constant->set_ssa_temp_index( |
| 1493 owner_->caller_graph()->alloc_ssa_temp_index()); | 1506 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1494 StrictCompareInstr* compare = | 1507 StrictCompareInstr* compare = |
| 1495 new StrictCompareInstr(call_->instance_call()->token_pos(), | 1508 new StrictCompareInstr(call_->instance_call()->token_pos(), |
| 1496 Token::kEQ_STRICT, | 1509 Token::kEQ_STRICT, |
| 1497 new Value(load_cid), | 1510 new Value(load_cid), |
| 1498 new Value(cid_constant), | 1511 new Value(cid_constant), |
| 1499 false); // No number check. | 1512 false); // No number check. |
| 1500 BranchInstr* branch = new BranchInstr(compare); | 1513 BranchInstr* branch = new BranchInstr(compare); |
| 1501 branch->InheritDeoptTarget(call_); | 1514 branch->InheritDeoptTarget(isolate(), call_); |
| 1502 AppendInstruction(AppendInstruction(cursor, cid_constant), branch); | 1515 AppendInstruction(AppendInstruction(cursor, cid_constant), branch); |
| 1503 current_block->set_last_instruction(branch); | 1516 current_block->set_last_instruction(branch); |
| 1504 cursor = NULL; | 1517 cursor = NULL; |
| 1505 | 1518 |
| 1506 // 2. Handle a match by linking to the inlined body. There are three | 1519 // 2. Handle a match by linking to the inlined body. There are three |
| 1507 // cases (unshared, shared first predecessor, and shared subsequent | 1520 // cases (unshared, shared first predecessor, and shared subsequent |
| 1508 // predecessors). | 1521 // predecessors). |
| 1509 BlockEntryInstr* callee_entry = inlined_entries_[i]; | 1522 BlockEntryInstr* callee_entry = inlined_entries_[i]; |
| 1510 TargetEntryInstr* true_target = NULL; | 1523 TargetEntryInstr* true_target = NULL; |
| 1511 if (callee_entry->IsGraphEntry()) { | 1524 if (callee_entry->IsGraphEntry()) { |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1523 } else { | 1536 } else { |
| 1524 // Shared inlined body and this is a subsequent entry. We have | 1537 // Shared inlined body and this is a subsequent entry. We have |
| 1525 // already constructed a join. We need a fresh target that jumps to | 1538 // already constructed a join. We need a fresh target that jumps to |
| 1526 // the join. | 1539 // the join. |
| 1527 JoinEntryInstr* join = callee_entry->AsJoinEntry(); | 1540 JoinEntryInstr* join = callee_entry->AsJoinEntry(); |
| 1528 ASSERT(join != NULL); | 1541 ASSERT(join != NULL); |
| 1529 ASSERT(join->dominator() != NULL); | 1542 ASSERT(join->dominator() != NULL); |
| 1530 true_target = | 1543 true_target = |
| 1531 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1544 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), |
| 1532 call_->GetBlock()->try_index()); | 1545 call_->GetBlock()->try_index()); |
| 1533 true_target->InheritDeoptTarget(join); | 1546 true_target->InheritDeoptTarget(isolate(), join); |
| 1534 GotoInstr* goto_join = new GotoInstr(join); | 1547 GotoInstr* goto_join = new GotoInstr(join); |
| 1535 goto_join->InheritDeoptTarget(join); | 1548 goto_join->InheritDeoptTarget(isolate(), join); |
| 1536 true_target->LinkTo(goto_join); | 1549 true_target->LinkTo(goto_join); |
| 1537 true_target->set_last_instruction(goto_join); | 1550 true_target->set_last_instruction(goto_join); |
| 1538 } | 1551 } |
| 1539 *branch->true_successor_address() = true_target; | 1552 *branch->true_successor_address() = true_target; |
| 1540 current_block->AddDominatedBlock(true_target); | 1553 current_block->AddDominatedBlock(true_target); |
| 1541 | 1554 |
| 1542 // 3. Prepare to handle a match failure on the next iteration or the | 1555 // 3. Prepare to handle a match failure on the next iteration or the |
| 1543 // fall-through code below for non-inlined variants. | 1556 // fall-through code below for non-inlined variants. |
| 1544 TargetEntryInstr* false_target = | 1557 TargetEntryInstr* false_target = |
| 1545 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1558 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), |
| 1546 call_->GetBlock()->try_index()); | 1559 call_->GetBlock()->try_index()); |
| 1547 false_target->InheritDeoptTarget(call_); | 1560 false_target->InheritDeoptTarget(isolate(), call_); |
| 1548 *branch->false_successor_address() = false_target; | 1561 *branch->false_successor_address() = false_target; |
| 1549 current_block->AddDominatedBlock(false_target); | 1562 current_block->AddDominatedBlock(false_target); |
| 1550 cursor = current_block = false_target; | 1563 cursor = current_block = false_target; |
| 1551 } | 1564 } |
| 1552 } | 1565 } |
| 1553 | 1566 |
| 1554 // Handle any non-inlined variants. | 1567 // Handle any non-inlined variants. |
| 1555 if (!non_inlined_variants_.is_empty()) { | 1568 if (!non_inlined_variants_.is_empty()) { |
| 1556 // Move push arguments of the call. | 1569 // Move push arguments of the call. |
| 1557 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1570 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 1572 new_checks.AddReceiverCheck(non_inlined_variants_[i].cid, | 1585 new_checks.AddReceiverCheck(non_inlined_variants_[i].cid, |
| 1573 *non_inlined_variants_[i].target, | 1586 *non_inlined_variants_[i].target, |
| 1574 non_inlined_variants_[i].count); | 1587 non_inlined_variants_[i].count); |
| 1575 } | 1588 } |
| 1576 PolymorphicInstanceCallInstr* fallback_call = | 1589 PolymorphicInstanceCallInstr* fallback_call = |
| 1577 new PolymorphicInstanceCallInstr(call_->instance_call(), | 1590 new PolymorphicInstanceCallInstr(call_->instance_call(), |
| 1578 new_checks, | 1591 new_checks, |
| 1579 true); // With checks. | 1592 true); // With checks. |
| 1580 fallback_call->set_ssa_temp_index( | 1593 fallback_call->set_ssa_temp_index( |
| 1581 owner_->caller_graph()->alloc_ssa_temp_index()); | 1594 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1582 fallback_call->InheritDeoptTarget(call_); | 1595 fallback_call->InheritDeoptTarget(isolate(), call_); |
| 1583 ReturnInstr* fallback_return = | 1596 ReturnInstr* fallback_return = |
| 1584 new ReturnInstr(call_->instance_call()->token_pos(), | 1597 new ReturnInstr(call_->instance_call()->token_pos(), |
| 1585 new Value(fallback_call)); | 1598 new Value(fallback_call)); |
| 1586 fallback_return->InheritDeoptTargetAfter(call_); | 1599 fallback_return->InheritDeoptTargetAfter(isolate(), call_); |
| 1587 AppendInstruction(AppendInstruction(cursor, fallback_call), | 1600 AppendInstruction(AppendInstruction(cursor, fallback_call), |
| 1588 fallback_return); | 1601 fallback_return); |
| 1589 exit_collector_->AddExit(fallback_return); | 1602 exit_collector_->AddExit(fallback_return); |
| 1590 cursor = NULL; | 1603 cursor = NULL; |
| 1591 } else { | 1604 } else { |
| 1592 // Remove push arguments of the call. | 1605 // Remove push arguments of the call. |
| 1593 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1606 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
| 1594 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1607 PushArgumentInstr* push = call_->PushArgumentAt(i); |
| 1595 push->ReplaceUsesWith(push->value()->definition()); | 1608 push->ReplaceUsesWith(push->value()->definition()); |
| 1596 push->RemoveFromGraph(); | 1609 push->RemoveFromGraph(); |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1704 OS::Print("After Inlining of %s\n", flow_graph_-> | 1717 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1705 parsed_function().function().ToFullyQualifiedCString()); | 1718 parsed_function().function().ToFullyQualifiedCString()); |
| 1706 FlowGraphPrinter printer(*flow_graph_); | 1719 FlowGraphPrinter printer(*flow_graph_); |
| 1707 printer.PrintBlocks(); | 1720 printer.PrintBlocks(); |
| 1708 } | 1721 } |
| 1709 } | 1722 } |
| 1710 } | 1723 } |
| 1711 } | 1724 } |
| 1712 | 1725 |
| 1713 } // namespace dart | 1726 } // namespace dart |
| OLD | NEW |