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 #if !defined(DART_PRECOMPILED_RUNTIME) | 4 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 5 #include "vm/flow_graph_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
| 6 | 6 |
| 7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
| 8 #include "vm/precompiler.h" | 8 #include "vm/precompiler.h" |
| 9 #include "vm/block_scheduler.h" | 9 #include "vm/block_scheduler.h" |
| 10 #include "vm/branch_optimizer.h" | 10 #include "vm/branch_optimizer.h" |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 425 GrowableArray<StaticCallInfo> static_calls_; | 425 GrowableArray<StaticCallInfo> static_calls_; |
| 426 GrowableArray<ClosureCallInfo> closure_calls_; | 426 GrowableArray<ClosureCallInfo> closure_calls_; |
| 427 GrowableArray<InstanceCallInfo> instance_calls_; | 427 GrowableArray<InstanceCallInfo> instance_calls_; |
| 428 | 428 |
| 429 DISALLOW_COPY_AND_ASSIGN(CallSites); | 429 DISALLOW_COPY_AND_ASSIGN(CallSites); |
| 430 }; | 430 }; |
| 431 | 431 |
| 432 | 432 |
| 433 struct InlinedCallData { | 433 struct InlinedCallData { |
| 434 InlinedCallData(Definition* call, | 434 InlinedCallData(Definition* call, |
| 435 intptr_t first_param_index, // 1 if type args are passed. | |
| 435 GrowableArray<Value*>* arguments, | 436 GrowableArray<Value*>* arguments, |
| 436 const Function& caller, | 437 const Function& caller, |
| 437 intptr_t caller_inlining_id) | 438 intptr_t caller_inlining_id) |
| 438 : call(call), | 439 : call(call), |
| 440 first_param_index(first_param_index), | |
| 439 arguments(arguments), | 441 arguments(arguments), |
| 440 callee_graph(NULL), | 442 callee_graph(NULL), |
| 441 parameter_stubs(NULL), | 443 parameter_stubs(NULL), |
| 442 exit_collector(NULL), | 444 exit_collector(NULL), |
| 443 caller(caller), | 445 caller(caller), |
| 444 caller_inlining_id_(caller_inlining_id) {} | 446 caller_inlining_id(caller_inlining_id) {} |
| 445 | 447 |
| 446 Definition* call; | 448 Definition* call; |
| 449 const intptr_t first_param_index; | |
| 447 GrowableArray<Value*>* arguments; | 450 GrowableArray<Value*>* arguments; |
| 448 FlowGraph* callee_graph; | 451 FlowGraph* callee_graph; |
| 449 ZoneGrowableArray<Definition*>* parameter_stubs; | 452 ZoneGrowableArray<Definition*>* parameter_stubs; |
| 450 InlineExitCollector* exit_collector; | 453 InlineExitCollector* exit_collector; |
| 451 const Function& caller; | 454 const Function& caller; |
| 452 const intptr_t caller_inlining_id_; | 455 const intptr_t caller_inlining_id; |
| 453 }; | 456 }; |
| 454 | 457 |
| 455 | 458 |
| 456 class CallSiteInliner; | 459 class CallSiteInliner; |
| 457 | 460 |
| 458 class PolymorphicInliner : public ValueObject { | 461 class PolymorphicInliner : public ValueObject { |
| 459 public: | 462 public: |
| 460 PolymorphicInliner(CallSiteInliner* owner, | 463 PolymorphicInliner(CallSiteInliner* owner, |
| 461 PolymorphicInstanceCallInstr* call, | 464 PolymorphicInstanceCallInstr* call, |
| 462 const Function& caller_function, | 465 const Function& caller_function, |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 507 val = metadata.At(i); | 510 val = metadata.At(i); |
| 508 if (val.IsString() && String::Cast(val).Equals(annotation)) { | 511 if (val.IsString() && String::Cast(val).Equals(annotation)) { |
| 509 return true; | 512 return true; |
| 510 } | 513 } |
| 511 } | 514 } |
| 512 } | 515 } |
| 513 return false; | 516 return false; |
| 514 } | 517 } |
| 515 | 518 |
| 516 | 519 |
| 520 static void InlineCall(Zone* zone, | |
| 521 FlowGraph* caller_graph, | |
| 522 InlinedCallData* call_data, | |
| 523 const TargetInfo* target_info) { | |
| 524 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); | |
| 525 const bool is_polymorphic = call_data->call->IsPolymorphicInstanceCall(); | |
| 526 ASSERT(is_polymorphic == (target_info != NULL)); | |
| 527 FlowGraph* callee_graph = call_data->callee_graph; | |
| 528 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); | |
| 529 if (!is_polymorphic) { | |
| 530 // Plug result in the caller graph. | |
| 531 InlineExitCollector* exit_collector = call_data->exit_collector; | |
| 532 exit_collector->PrepareGraphs(callee_graph); | |
| 533 exit_collector->ReplaceCall(callee_entry); | |
| 534 } | |
| 535 | |
| 536 // Replace each stub with the actual argument or the caller's constant. | |
| 537 // Nulls denote optional parameters for which no actual was given. | |
| 538 const intptr_t first_param_index = call_data->first_param_index; | |
| 539 // When first_param_index > 0, the stub and actual argument processed in the | |
| 540 // first loop iteration represent a passed-in type argument vector. | |
| 541 GrowableArray<Value*>* arguments = call_data->arguments; | |
| 542 intptr_t first_arg_stub_index = 0; | |
| 543 if (arguments->length() != call_data->parameter_stubs->length()) { | |
| 544 ASSERT(arguments->length() == call_data->parameter_stubs->length() - 1); | |
| 545 ASSERT(first_param_index == 0); | |
| 546 // The first parameter stub accepts an optional type argument vector, but | |
| 547 // none was provided in arguments. | |
| 548 first_arg_stub_index = 1; | |
| 549 } | |
| 550 for (intptr_t i = 0; i < arguments->length(); ++i) { | |
| 551 Value* actual = (*arguments)[i]; | |
| 552 if (is_polymorphic && (i == first_param_index)) { | |
| 553 // Replace the receiver argument with a redefinition to prevent code from | |
| 554 // the inlined body from being hoisted above the inlined entry. | |
| 555 RedefinitionInstr* redefinition = | |
| 556 new (zone) RedefinitionInstr(actual->Copy(zone)); | |
| 557 redefinition->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index()); | |
| 558 if (target_info->IsSingleCid()) { | |
| 559 redefinition->UpdateType(CompileType::FromCid(target_info->cid_start)); | |
| 560 } | |
| 561 redefinition->InsertAfter(callee_entry); | |
| 562 Definition* stub = (*call_data->parameter_stubs)[first_arg_stub_index]; | |
|
Vyacheslav Egorov (Google)
2017/07/03 16:15:43
I think this is the problematic place. This should
regis
2017/07/05 18:41:29
Good catch! If first_arg_stub_index is 1, i has to
| |
| 563 stub->ReplaceUsesWith(redefinition); | |
| 564 } else if (actual != NULL) { | |
| 565 Definition* stub = | |
| 566 (*call_data->parameter_stubs)[first_arg_stub_index + i]; | |
| 567 stub->ReplaceUsesWith(actual->definition()); | |
| 568 } | |
| 569 } | |
| 570 | |
| 571 if (!is_polymorphic) { | |
| 572 // Remove push arguments of the call. | |
| 573 Definition* call = call_data->call; | |
| 574 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 575 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 576 push->ReplaceUsesWith(push->value()->definition()); | |
| 577 push->RemoveFromGraph(); | |
| 578 } | |
| 579 } | |
| 580 | |
| 581 // Replace remaining constants with uses by constants in the caller's | |
| 582 // initial definitions. | |
| 583 GrowableArray<Definition*>* defns = | |
| 584 callee_graph->graph_entry()->initial_definitions(); | |
| 585 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 586 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 587 if ((constant != NULL) && constant->HasUses()) { | |
| 588 constant->ReplaceUsesWith(caller_graph->GetConstant(constant->value())); | |
| 589 } | |
| 590 SpecialParameterInstr* param = (*defns)[i]->AsSpecialParameter(); | |
| 591 if ((param != NULL) && param->HasUses()) { | |
| 592 if (param->kind() == SpecialParameterInstr::kContext) { | |
| 593 ASSERT(!is_polymorphic); | |
|
Vyacheslav Egorov (Google)
2017/07/03 16:15:43
maybe leave a comment here that we currently don't
regis
2017/07/05 18:41:29
Done.
| |
| 594 ASSERT(call_data->call->IsClosureCall()); | |
| 595 LoadFieldInstr* context_load = new (zone) LoadFieldInstr( | |
| 596 new Value((*arguments)[first_param_index]->definition()), | |
| 597 Closure::context_offset(), | |
| 598 AbstractType::ZoneHandle(zone, AbstractType::null()), | |
| 599 call_data->call->token_pos()); | |
| 600 context_load->set_is_immutable(true); | |
| 601 context_load->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index()); | |
| 602 context_load->InsertBefore(callee_entry->next()); | |
| 603 param->ReplaceUsesWith(context_load); | |
| 604 } else { | |
| 605 ASSERT(param->kind() == SpecialParameterInstr::kTypeArgs); | |
| 606 Definition* type_args; | |
| 607 if (first_param_index > 0) { | |
| 608 type_args = (*arguments)[0]->definition(); | |
| 609 } else { | |
| 610 type_args = callee_graph->constant_null(); | |
| 611 } | |
| 612 param->ReplaceUsesWith(type_args); | |
| 613 } | |
| 614 } | |
| 615 } | |
| 616 | |
| 617 // Check that inlining maintains use lists. | |
| 618 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph->VerifyUseLists()); | |
| 619 } | |
| 620 | |
| 621 | |
| 517 class CallSiteInliner : public ValueObject { | 622 class CallSiteInliner : public ValueObject { |
| 518 public: | 623 public: |
| 519 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) | 624 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) |
| 520 : inliner_(inliner), | 625 : inliner_(inliner), |
| 521 caller_graph_(inliner->flow_graph()), | 626 caller_graph_(inliner->flow_graph()), |
| 522 inlined_(false), | 627 inlined_(false), |
| 523 initial_size_(inliner->flow_graph()->InstructionCount()), | 628 initial_size_(inliner->flow_graph()->InstructionCount()), |
| 524 inlined_size_(0), | 629 inlined_size_(0), |
| 525 inlined_recursive_call_(false), | 630 inlined_recursive_call_(false), |
| 526 inlining_depth_(1), | 631 inlining_depth_(1), |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 return true; | 671 return true; |
| 567 } | 672 } |
| 568 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 673 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 569 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { | 674 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { |
| 570 return true; | 675 return true; |
| 571 } | 676 } |
| 572 return false; | 677 return false; |
| 573 } | 678 } |
| 574 | 679 |
| 575 void InlineCalls() { | 680 void InlineCalls() { |
| 576 // If inlining depth is less then one abort. | 681 // If inlining depth is less than one abort. |
| 577 if (inlining_depth_threshold_ < 1) return; | 682 if (inlining_depth_threshold_ < 1) return; |
| 578 if (caller_graph_->function().deoptimization_counter() >= | 683 if (caller_graph_->function().deoptimization_counter() >= |
| 579 FLAG_deoptimization_counter_inlining_threshold) { | 684 FLAG_deoptimization_counter_inlining_threshold) { |
| 580 return; | 685 return; |
| 581 } | 686 } |
| 582 // Create two call site collections to swap between. | 687 // Create two call site collections to swap between. |
| 583 CallSites sites1(caller_graph_, inlining_depth_threshold_); | 688 CallSites sites1(caller_graph_, inlining_depth_threshold_); |
| 584 CallSites sites2(caller_graph_, inlining_depth_threshold_); | 689 CallSites sites2(caller_graph_, inlining_depth_threshold_); |
| 585 CallSites* call_sites_temp = NULL; | 690 CallSites* call_sites_temp = NULL; |
| 586 collected_call_sites_ = &sites1; | 691 collected_call_sites_ = &sites1; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 822 inliner_->precompiler_->TryApplyFeedback( | 927 inliner_->precompiler_->TryApplyFeedback( |
| 823 parsed_function->function(), callee_graph); | 928 parsed_function->function(), callee_graph); |
| 824 } | 929 } |
| 825 } | 930 } |
| 826 #endif | 931 #endif |
| 827 | 932 |
| 828 // The parameter stubs are a copy of the actual arguments providing | 933 // The parameter stubs are a copy of the actual arguments providing |
| 829 // concrete information about the values, for example constant values, | 934 // concrete information about the values, for example constant values, |
| 830 // without linking between the caller and callee graphs. | 935 // without linking between the caller and callee graphs. |
| 831 // TODO(zerny): Put more information in the stubs, eg, type information. | 936 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 937 const intptr_t first_actual_param_index = call_data->first_param_index; | |
| 938 const intptr_t inlined_type_args_param = | |
| 939 (FLAG_reify_generic_functions && function.IsGeneric()) ? 1 : 0; | |
| 940 const intptr_t num_inlined_params = | |
| 941 inlined_type_args_param + function.NumParameters(); | |
| 832 ZoneGrowableArray<Definition*>* param_stubs = | 942 ZoneGrowableArray<Definition*>* param_stubs = |
| 833 new (Z) ZoneGrowableArray<Definition*>(function.NumParameters()); | 943 new (Z) ZoneGrowableArray<Definition*>(num_inlined_params); |
| 834 | 944 |
| 945 // Create a ConstantInstr as Definition for the type arguments, if any. | |
| 946 if (first_actual_param_index > 0) { | |
| 947 // A type argument vector is explicitly passed. | |
| 948 param_stubs->Add( | |
| 949 CreateParameterStub(-1, (*arguments)[0], callee_graph)); | |
| 950 } else if (inlined_type_args_param > 0) { | |
| 951 // No type argument vector is passed to the generic function, | |
| 952 // pass a null vector, which is the same as a vector of dynamic types. | |
| 953 param_stubs->Add(callee_graph->GetConstant(Object::ZoneHandle())); | |
| 954 } | |
| 835 // Create a parameter stub for each fixed positional parameter. | 955 // Create a parameter stub for each fixed positional parameter. |
| 836 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 956 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 837 param_stubs->Add( | 957 param_stubs->Add(CreateParameterStub( |
| 838 CreateParameterStub(i, (*arguments)[i], callee_graph)); | 958 i, (*arguments)[first_actual_param_index + i], callee_graph)); |
| 839 } | 959 } |
| 840 | 960 |
| 841 // If the callee has optional parameters, rebuild the argument and stub | 961 // If the callee has optional parameters, rebuild the argument and stub |
| 842 // arrays so that actual arguments are in one-to-one with the formal | 962 // arrays so that actual arguments are in one-to-one with the formal |
| 843 // parameters. | 963 // parameters. |
| 844 if (function.HasOptionalParameters()) { | 964 if (function.HasOptionalParameters()) { |
| 845 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); | 965 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); |
| 846 if (!AdjustForOptionalParameters(*parsed_function, argument_names, | 966 if (!AdjustForOptionalParameters( |
| 847 arguments, param_stubs, | 967 *parsed_function, first_actual_param_index, argument_names, |
| 848 callee_graph)) { | 968 arguments, param_stubs, callee_graph)) { |
| 849 function.set_is_inlinable(false); | 969 function.set_is_inlinable(false); |
| 850 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); | 970 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); |
| 851 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, | 971 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, |
| 852 &function, call_data->call); | 972 &function, call_data->call); |
| 853 return false; | 973 return false; |
| 854 } | 974 } |
| 855 } | 975 } |
| 856 | 976 |
| 857 // After treating optional parameters the actual/formal count must | 977 // After treating optional parameters the actual/formal count must |
| 858 // match. | 978 // match. |
| 859 // TODO(regis): Consider type arguments in arguments. | 979 ASSERT(arguments->length() == |
| 860 if (arguments->length() != function.NumParameters()) { | 980 first_actual_param_index + function.NumParameters()); |
| 861 ASSERT(function.IsGeneric()); | 981 ASSERT(param_stubs->length() == |
| 862 ASSERT(arguments->length() == function.NumParameters() + 1); | 982 inlined_type_args_param + callee_graph->parameter_count()); |
| 863 TRACE_INLINING( | |
| 864 THR_Print(" Bailout: unsupported type arguments\n")); | |
| 865 PRINT_INLINING_TREE("Unsupported type arguments", &call_data->caller, | |
| 866 &function, call_data->call); | |
| 867 return false; | |
| 868 } | |
| 869 ASSERT(param_stubs->length() == callee_graph->parameter_count()); | |
| 870 | 983 |
| 871 // Update try-index of the callee graph. | 984 // Update try-index of the callee graph. |
| 872 BlockEntryInstr* call_block = call_data->call->GetBlock(); | 985 BlockEntryInstr* call_block = call_data->call->GetBlock(); |
| 873 if (call_block->InsideTryBlock()) { | 986 if (call_block->InsideTryBlock()) { |
| 874 intptr_t try_index = call_block->try_index(); | 987 intptr_t try_index = call_block->try_index(); |
| 875 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); | 988 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); |
| 876 !it.Done(); it.Advance()) { | 989 !it.Done(); it.Advance()) { |
| 877 BlockEntryInstr* block = it.Current(); | 990 BlockEntryInstr* block = it.Current(); |
| 878 block->set_try_index(try_index); | 991 block->set_try_index(try_index); |
| 879 } | 992 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 } | 1126 } |
| 1014 // When inlined, we add the deferred prefixes of the callee to the | 1127 // When inlined, we add the deferred prefixes of the callee to the |
| 1015 // caller's list of deferred prefixes. | 1128 // caller's list of deferred prefixes. |
| 1016 caller_graph()->AddToDeferredPrefixes( | 1129 caller_graph()->AddToDeferredPrefixes( |
| 1017 callee_graph->deferred_prefixes()); | 1130 callee_graph->deferred_prefixes()); |
| 1018 | 1131 |
| 1019 FlowGraphInliner::SetInliningId( | 1132 FlowGraphInliner::SetInliningId( |
| 1020 callee_graph, | 1133 callee_graph, |
| 1021 inliner_->NextInlineId(callee_graph->function(), | 1134 inliner_->NextInlineId(callee_graph->function(), |
| 1022 call_data->call->token_pos(), | 1135 call_data->call->token_pos(), |
| 1023 call_data->caller_inlining_id_)); | 1136 call_data->caller_inlining_id)); |
| 1024 TRACE_INLINING(THR_Print(" Success\n")); | 1137 TRACE_INLINING(THR_Print(" Success\n")); |
| 1025 TRACE_INLINING(THR_Print(" with size %" Pd "\n", | 1138 TRACE_INLINING(THR_Print(" with size %" Pd "\n", |
| 1026 function.optimized_instruction_count())); | 1139 function.optimized_instruction_count())); |
| 1027 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); | 1140 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); |
| 1028 return true; | 1141 return true; |
| 1029 } else { | 1142 } else { |
| 1030 error = thread()->sticky_error(); | 1143 error = thread()->sticky_error(); |
| 1031 thread()->clear_sticky_error(); | 1144 thread()->clear_sticky_error(); |
| 1032 | 1145 |
| 1033 if (error.IsLanguageError() && | 1146 if (error.IsLanguageError() && |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1114 for (int t = 0; t < depth; t++) { | 1227 for (int t = 0; t < depth; t++) { |
| 1115 THR_Print(" "); | 1228 THR_Print(" "); |
| 1116 } | 1229 } |
| 1117 THR_Print("NO %" Pd " %s - %s\n", info.call_instr->GetDeoptId(), | 1230 THR_Print("NO %" Pd " %s - %s\n", info.call_instr->GetDeoptId(), |
| 1118 info.inlined->ToQualifiedCString(), info.bailout_reason); | 1231 info.inlined->ToQualifiedCString(), info.bailout_reason); |
| 1119 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 1232 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
| 1120 } | 1233 } |
| 1121 } | 1234 } |
| 1122 } | 1235 } |
| 1123 | 1236 |
| 1124 void InlineCall(InlinedCallData* call_data) { | |
| 1125 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); | |
| 1126 FlowGraph* callee_graph = call_data->callee_graph; | |
| 1127 TargetEntryInstr* callee_entry = | |
| 1128 callee_graph->graph_entry()->normal_entry(); | |
| 1129 // Plug result in the caller graph. | |
| 1130 InlineExitCollector* exit_collector = call_data->exit_collector; | |
| 1131 exit_collector->PrepareGraphs(callee_graph); | |
| 1132 exit_collector->ReplaceCall(callee_entry); | |
| 1133 | |
| 1134 // Replace each stub with the actual argument or the caller's constant. | |
| 1135 // Nulls denote optional parameters for which no actual was given. | |
| 1136 GrowableArray<Value*>* arguments = call_data->arguments; | |
| 1137 for (intptr_t i = 0; i < arguments->length(); ++i) { | |
| 1138 Definition* stub = (*call_data->parameter_stubs)[i]; | |
| 1139 Value* actual = (*arguments)[i]; | |
| 1140 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); | |
| 1141 } | |
| 1142 | |
| 1143 // Remove push arguments of the call. | |
| 1144 Definition* call = call_data->call; | |
| 1145 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 1146 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 1147 push->ReplaceUsesWith(push->value()->definition()); | |
| 1148 push->RemoveFromGraph(); | |
| 1149 } | |
| 1150 | |
| 1151 // Replace remaining constants with uses by constants in the caller's | |
| 1152 // initial definitions. | |
| 1153 GrowableArray<Definition*>* defns = | |
| 1154 callee_graph->graph_entry()->initial_definitions(); | |
| 1155 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 1156 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 1157 if ((constant != NULL) && constant->HasUses()) { | |
| 1158 constant->ReplaceUsesWith( | |
| 1159 caller_graph_->GetConstant(constant->value())); | |
| 1160 } | |
| 1161 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | |
| 1162 if ((context != NULL) && context->HasUses()) { | |
| 1163 ASSERT(call->IsClosureCall()); | |
| 1164 LoadFieldInstr* context_load = new (Z) LoadFieldInstr( | |
| 1165 new Value((*arguments)[0]->definition()), Closure::context_offset(), | |
| 1166 AbstractType::ZoneHandle(zone(), AbstractType::null()), | |
| 1167 call_data->call->token_pos()); | |
| 1168 context_load->set_is_immutable(true); | |
| 1169 context_load->set_ssa_temp_index(caller_graph_->alloc_ssa_temp_index()); | |
| 1170 context_load->InsertBefore(callee_entry->next()); | |
| 1171 context->ReplaceUsesWith(context_load); | |
| 1172 } | |
| 1173 } | |
| 1174 | |
| 1175 // Check that inlining maintains use lists. | |
| 1176 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists()); | |
| 1177 } | |
| 1178 | |
| 1179 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { | 1237 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { |
| 1180 intptr_t count = 0; | 1238 intptr_t count = 0; |
| 1181 for (intptr_t i = 0; i < arguments.length(); i++) { | 1239 for (intptr_t i = 0; i < arguments.length(); i++) { |
| 1182 if (arguments[i]->BindsToConstant()) count++; | 1240 if (arguments[i]->BindsToConstant()) count++; |
| 1183 } | 1241 } |
| 1184 return count; | 1242 return count; |
| 1185 } | 1243 } |
| 1186 | 1244 |
| 1187 // Parse a function reusing the cache if possible. | 1245 // Parse a function reusing the cache if possible. |
| 1188 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 1246 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1221 } | 1279 } |
| 1222 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), | 1280 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), |
| 1223 &call->function(), call); | 1281 &call->function(), call); |
| 1224 continue; | 1282 continue; |
| 1225 } | 1283 } |
| 1226 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1284 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1227 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1285 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1228 arguments.Add(call->PushArgumentAt(i)->value()); | 1286 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1229 } | 1287 } |
| 1230 InlinedCallData call_data( | 1288 InlinedCallData call_data( |
| 1231 call, &arguments, call_info[call_idx].caller(), | 1289 call, call->FirstParamIndex(), &arguments, |
| 1290 call_info[call_idx].caller(), | |
| 1232 call_info[call_idx].caller_graph->inlining_id()); | 1291 call_info[call_idx].caller_graph->inlining_id()); |
| 1233 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1292 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 1234 InlineCall(&call_data); | 1293 InlineCall(zone(), caller_graph_, &call_data, NULL); |
| 1235 } | 1294 } |
| 1236 } | 1295 } |
| 1237 } | 1296 } |
| 1238 | 1297 |
| 1239 void InlineClosureCalls() { | 1298 void InlineClosureCalls() { |
| 1240 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1299 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
| 1241 inlining_call_sites_->closure_calls(); | 1300 inlining_call_sites_->closure_calls(); |
| 1242 TRACE_INLINING( | 1301 TRACE_INLINING( |
| 1243 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); | 1302 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); |
| 1244 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1303 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| (...skipping 22 matching lines...) Expand all Loading... | |
| 1267 call->ArgumentCount() < target.num_fixed_parameters()) { | 1326 call->ArgumentCount() < target.num_fixed_parameters()) { |
| 1268 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); | 1327 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); |
| 1269 continue; | 1328 continue; |
| 1270 } | 1329 } |
| 1271 | 1330 |
| 1272 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1331 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1273 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1332 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1274 arguments.Add(call->PushArgumentAt(i)->value()); | 1333 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1275 } | 1334 } |
| 1276 InlinedCallData call_data( | 1335 InlinedCallData call_data( |
| 1277 call, &arguments, call_info[call_idx].caller(), | 1336 call, call->FirstParamIndex(), &arguments, |
| 1337 call_info[call_idx].caller(), | |
| 1278 call_info[call_idx].caller_graph->inlining_id()); | 1338 call_info[call_idx].caller_graph->inlining_id()); |
| 1279 if (TryInlining(target, call->argument_names(), &call_data)) { | 1339 if (TryInlining(target, call->argument_names(), &call_data)) { |
| 1280 InlineCall(&call_data); | 1340 InlineCall(zone(), caller_graph_, &call_data, NULL); |
| 1281 } | 1341 } |
| 1282 } | 1342 } |
| 1283 } | 1343 } |
| 1284 | 1344 |
| 1285 void InlineInstanceCalls() { | 1345 void InlineInstanceCalls() { |
| 1286 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1346 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
| 1287 inlining_call_sites_->instance_calls(); | 1347 inlining_call_sites_->instance_calls(); |
| 1288 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", | 1348 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", |
| 1289 call_info.length())); | 1349 call_info.length())); |
| 1290 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1350 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 1291 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1351 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 1292 // PolymorphicInliner introduces deoptimization paths. | 1352 // PolymorphicInliner introduces deoptimization paths. |
| 1293 if (!call->complete() && !FLAG_polymorphic_with_deopt) { | 1353 if (!call->complete() && !FLAG_polymorphic_with_deopt) { |
| 1294 TRACE_INLINING( | 1354 TRACE_INLINING( |
| 1295 THR_Print(" => %s\n Bailout: call with checks\n", | 1355 THR_Print(" => %s\n Bailout: call with checks\n", |
| 1296 call->instance_call()->function_name().ToCString())); | 1356 call->instance_call()->function_name().ToCString())); |
| 1297 continue; | 1357 continue; |
| 1298 } | 1358 } |
| 1299 const Function& cl = call_info[call_idx].caller(); | 1359 const Function& cl = call_info[call_idx].caller(); |
| 1300 intptr_t caller_inlining_id = | 1360 intptr_t caller_inlining_id = |
| 1301 call_info[call_idx].caller_graph->inlining_id(); | 1361 call_info[call_idx].caller_graph->inlining_id(); |
| 1302 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1362 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
| 1303 inliner.Inline(); | 1363 inliner.Inline(); |
| 1304 } | 1364 } |
| 1305 } | 1365 } |
| 1306 | 1366 |
| 1307 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, | 1367 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, |
| 1368 intptr_t first_param_index, | |
| 1308 const Array& argument_names, | 1369 const Array& argument_names, |
| 1309 GrowableArray<Value*>* arguments, | 1370 GrowableArray<Value*>* arguments, |
| 1310 ZoneGrowableArray<Definition*>* param_stubs, | 1371 ZoneGrowableArray<Definition*>* param_stubs, |
| 1311 FlowGraph* callee_graph) { | 1372 FlowGraph* callee_graph) { |
| 1312 const Function& function = parsed_function.function(); | 1373 const Function& function = parsed_function.function(); |
| 1313 // The language and this code does not support both optional positional | 1374 // The language and this code does not support both optional positional |
| 1314 // and optional named parameters for the same function. | 1375 // and optional named parameters for the same function. |
| 1315 ASSERT(!function.HasOptionalPositionalParameters() || | 1376 ASSERT(!function.HasOptionalPositionalParameters() || |
| 1316 !function.HasOptionalNamedParameters()); | 1377 !function.HasOptionalNamedParameters()); |
| 1317 | 1378 |
| 1318 // TODO(regis): Consider type arguments in arguments. | |
| 1319 intptr_t arg_count = arguments->length(); | 1379 intptr_t arg_count = arguments->length(); |
| 1320 intptr_t param_count = function.NumParameters(); | 1380 intptr_t param_count = function.NumParameters(); |
| 1321 intptr_t fixed_param_count = function.num_fixed_parameters(); | 1381 intptr_t fixed_param_count = function.num_fixed_parameters(); |
| 1322 ASSERT(fixed_param_count <= arg_count); | 1382 ASSERT(fixed_param_count <= arg_count - first_param_index); |
| 1323 ASSERT(arg_count <= param_count); | 1383 ASSERT(arg_count - first_param_index <= param_count); |
| 1324 | 1384 |
| 1325 if (function.HasOptionalPositionalParameters()) { | 1385 if (function.HasOptionalPositionalParameters()) { |
| 1326 // Create a stub for each optional positional parameters with an actual. | 1386 // Create a stub for each optional positional parameters with an actual. |
| 1327 for (intptr_t i = fixed_param_count; i < arg_count; ++i) { | 1387 for (intptr_t i = first_param_index + fixed_param_count; i < arg_count; |
| 1388 ++i) { | |
| 1328 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 1389 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 1329 } | 1390 } |
| 1330 ASSERT(function.NumOptionalPositionalParameters() == | 1391 ASSERT(function.NumOptionalPositionalParameters() == |
| 1331 (param_count - fixed_param_count)); | 1392 (param_count - fixed_param_count)); |
| 1332 // For each optional positional parameter without an actual, add its | 1393 // For each optional positional parameter without an actual, add its |
| 1333 // default value. | 1394 // default value. |
| 1334 for (intptr_t i = arg_count; i < param_count; ++i) { | 1395 for (intptr_t i = arg_count - first_param_index; i < param_count; ++i) { |
| 1335 const Instance& object = | 1396 const Instance& object = |
| 1336 parsed_function.DefaultParameterValueAt(i - fixed_param_count); | 1397 parsed_function.DefaultParameterValueAt(i - fixed_param_count); |
| 1337 ConstantInstr* constant = new (Z) ConstantInstr(object); | 1398 ConstantInstr* constant = new (Z) ConstantInstr(object); |
| 1338 arguments->Add(NULL); | 1399 arguments->Add(NULL); |
| 1339 param_stubs->Add(constant); | 1400 param_stubs->Add(constant); |
| 1340 } | 1401 } |
| 1341 return true; | 1402 return true; |
| 1342 } | 1403 } |
| 1343 | 1404 |
| 1344 ASSERT(function.HasOptionalNamedParameters()); | 1405 ASSERT(function.HasOptionalNamedParameters()); |
| 1345 | 1406 |
| 1346 // Passed arguments must match fixed parameters plus named arguments. | 1407 // Passed arguments (not counting optional type args) must match fixed |
| 1408 // parameters plus named arguments. | |
| 1347 intptr_t argument_names_count = | 1409 intptr_t argument_names_count = |
| 1348 (argument_names.IsNull()) ? 0 : argument_names.Length(); | 1410 (argument_names.IsNull()) ? 0 : argument_names.Length(); |
| 1349 ASSERT(arg_count == (fixed_param_count + argument_names_count)); | 1411 ASSERT((arg_count - first_param_index) == |
| 1412 (fixed_param_count + argument_names_count)); | |
| 1350 | 1413 |
| 1351 // Fast path when no optional named parameters are given. | 1414 // Fast path when no optional named parameters are given. |
| 1352 if (argument_names_count == 0) { | 1415 if (argument_names_count == 0) { |
| 1353 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { | 1416 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { |
| 1354 arguments->Add(NULL); | 1417 arguments->Add(NULL); |
| 1355 param_stubs->Add(GetDefaultValue(i, parsed_function)); | 1418 param_stubs->Add(GetDefaultValue(i, parsed_function)); |
| 1356 } | 1419 } |
| 1357 return true; | 1420 return true; |
| 1358 } | 1421 } |
| 1359 | 1422 |
| 1360 // Otherwise, build a collection of name/argument pairs. | 1423 // Otherwise, build a collection of name/argument pairs. |
| 1361 GrowableArray<NamedArgument> named_args(argument_names_count); | 1424 GrowableArray<NamedArgument> named_args(argument_names_count); |
| 1362 for (intptr_t i = 0; i < argument_names.Length(); ++i) { | 1425 for (intptr_t i = 0; i < argument_names.Length(); ++i) { |
| 1363 String& arg_name = String::Handle(caller_graph_->zone()); | 1426 String& arg_name = String::Handle(caller_graph_->zone()); |
| 1364 arg_name ^= argument_names.At(i); | 1427 arg_name ^= argument_names.At(i); |
| 1365 named_args.Add( | 1428 named_args.Add(NamedArgument( |
| 1366 NamedArgument(&arg_name, (*arguments)[i + fixed_param_count])); | 1429 &arg_name, (*arguments)[first_param_index + fixed_param_count + i])); |
| 1367 } | 1430 } |
| 1368 | 1431 |
| 1369 // Truncate the arguments array to just fixed parameters. | 1432 // Truncate the arguments array to just type args and fixed parameters. |
| 1370 arguments->TruncateTo(fixed_param_count); | 1433 arguments->TruncateTo(first_param_index + fixed_param_count); |
| 1371 | 1434 |
| 1372 // For each optional named parameter, add the actual argument or its | 1435 // For each optional named parameter, add the actual argument or its |
| 1373 // default if no argument is passed. | 1436 // default if no argument is passed. |
| 1374 intptr_t match_count = 0; | 1437 intptr_t match_count = 0; |
| 1375 for (intptr_t i = fixed_param_count; i < param_count; ++i) { | 1438 for (intptr_t i = fixed_param_count; i < param_count; ++i) { |
| 1376 String& param_name = String::Handle(function.ParameterNameAt(i)); | 1439 String& param_name = String::Handle(function.ParameterNameAt(i)); |
| 1377 // Search for and add the named argument. | 1440 // Search for and add the named argument. |
| 1378 Value* arg = NULL; | 1441 Value* arg = NULL; |
| 1379 for (intptr_t j = 0; j < named_args.length(); ++j) { | 1442 for (intptr_t j = 0; j < named_args.length(); ++j) { |
| 1380 if (param_name.Equals(*named_args[j].name)) { | 1443 if (param_name.Equals(*named_args[j].name)) { |
| 1381 arg = named_args[j].value; | 1444 arg = named_args[j].value; |
| 1382 match_count++; | 1445 match_count++; |
| 1383 break; | 1446 break; |
| 1384 } | 1447 } |
| 1385 } | 1448 } |
| 1386 arguments->Add(arg); | 1449 arguments->Add(arg); |
| 1387 // Create a stub for the argument or use the parameter's default value. | 1450 // Create a stub for the argument or use the parameter's default value. |
| 1388 if (arg != NULL) { | 1451 if (arg != NULL) { |
| 1389 param_stubs->Add(CreateParameterStub(i, arg, callee_graph)); | 1452 param_stubs->Add( |
| 1453 CreateParameterStub(first_param_index + i, arg, callee_graph)); | |
| 1390 } else { | 1454 } else { |
| 1391 param_stubs->Add( | 1455 param_stubs->Add( |
| 1392 GetDefaultValue(i - fixed_param_count, parsed_function)); | 1456 GetDefaultValue(i - fixed_param_count, parsed_function)); |
| 1393 } | 1457 } |
| 1394 } | 1458 } |
| 1395 return argument_names_count == match_count; | 1459 return argument_names_count == match_count; |
| 1396 } | 1460 } |
| 1397 | 1461 |
| 1398 FlowGraphInliner* inliner_; | 1462 FlowGraphInliner* inliner_; |
| 1399 FlowGraph* caller_graph_; | 1463 FlowGraph* caller_graph_; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 target_info.IsSingleCid() && | 1586 target_info.IsSingleCid() && |
| 1523 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { | 1587 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
| 1524 owner_->inlined_ = true; | 1588 owner_->inlined_ = true; |
| 1525 return true; | 1589 return true; |
| 1526 } | 1590 } |
| 1527 | 1591 |
| 1528 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1592 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
| 1529 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1593 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
| 1530 arguments.Add(call_->PushArgumentAt(i)->value()); | 1594 arguments.Add(call_->PushArgumentAt(i)->value()); |
| 1531 } | 1595 } |
| 1532 InlinedCallData call_data(call_, &arguments, caller_function_, | 1596 InlinedCallData call_data(call_, call_->instance_call()->FirstParamIndex(), |
| 1533 caller_inlining_id_); | 1597 &arguments, caller_function_, caller_inlining_id_); |
| 1534 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); | 1598 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); |
| 1535 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), | 1599 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
| 1536 &call_data)) { | 1600 &call_data)) { |
| 1537 return false; | 1601 return false; |
| 1538 } | 1602 } |
| 1539 | 1603 |
| 1540 FlowGraph* callee_graph = call_data.callee_graph; | 1604 FlowGraph* callee_graph = call_data.callee_graph; |
| 1541 call_data.exit_collector->PrepareGraphs(callee_graph); | 1605 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1542 inlined_entries_.Add(callee_graph->graph_entry()); | 1606 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1543 exit_collector_->Union(call_data.exit_collector); | 1607 exit_collector_->Union(call_data.exit_collector); |
| 1544 | 1608 |
| 1545 // Replace parameter stubs and constants. Replace the receiver argument | 1609 InlineCall(zone(), owner_->caller_graph(), &call_data, &target_info); |
| 1546 // with a redefinition to prevent code from the inlined body from being | |
| 1547 // hoisted above the inlined entry. | |
| 1548 ASSERT(arguments.length() > 0); | |
| 1549 Value* actual = arguments[0]; | |
| 1550 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); | |
| 1551 redefinition->set_ssa_temp_index( | |
| 1552 owner_->caller_graph()->alloc_ssa_temp_index()); | |
| 1553 if (target_info.IsSingleCid()) { | |
| 1554 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); | |
| 1555 } | |
| 1556 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | |
| 1557 Definition* stub = (*call_data.parameter_stubs)[0]; | |
| 1558 stub->ReplaceUsesWith(redefinition); | |
| 1559 | |
| 1560 for (intptr_t i = 1; i < arguments.length(); ++i) { | |
| 1561 actual = arguments[i]; | |
| 1562 if (actual != NULL) { | |
| 1563 stub = (*call_data.parameter_stubs)[i]; | |
| 1564 stub->ReplaceUsesWith(actual->definition()); | |
| 1565 } | |
| 1566 } | |
| 1567 GrowableArray<Definition*>* defns = | |
| 1568 callee_graph->graph_entry()->initial_definitions(); | |
| 1569 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 1570 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 1571 if ((constant != NULL) && constant->HasUses()) { | |
| 1572 constant->ReplaceUsesWith( | |
| 1573 owner_->caller_graph()->GetConstant(constant->value())); | |
| 1574 } | |
| 1575 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | |
| 1576 if ((context != NULL) && context->HasUses()) { | |
| 1577 ASSERT(call_data.call->IsClosureCall()); | |
| 1578 LoadFieldInstr* context_load = new (Z) | |
| 1579 LoadFieldInstr(new Value(redefinition), Closure::context_offset(), | |
| 1580 AbstractType::ZoneHandle(zone(), AbstractType::null()), | |
| 1581 call_data.call->token_pos()); | |
| 1582 context_load->set_is_immutable(true); | |
| 1583 context_load->set_ssa_temp_index( | |
| 1584 owner_->caller_graph()->alloc_ssa_temp_index()); | |
| 1585 context_load->InsertAfter(redefinition); | |
| 1586 context->ReplaceUsesWith(context_load); | |
| 1587 } | |
| 1588 } | |
| 1589 return true; | 1610 return true; |
| 1590 } | 1611 } |
| 1591 | 1612 |
| 1592 | 1613 |
| 1593 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { | 1614 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { |
| 1594 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1615 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
| 1595 Value* input = second->InputAt(i); | 1616 Value* input = second->InputAt(i); |
| 1596 input->definition()->AddInputUse(input); | 1617 input->definition()->AddInputUse(input); |
| 1597 } | 1618 } |
| 1598 first->LinkTo(second); | 1619 first->LinkTo(second); |
| (...skipping 2168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3767 } | 3788 } |
| 3768 | 3789 |
| 3769 default: | 3790 default: |
| 3770 return false; | 3791 return false; |
| 3771 } | 3792 } |
| 3772 } | 3793 } |
| 3773 | 3794 |
| 3774 | 3795 |
| 3775 } // namespace dart | 3796 } // namespace dart |
| 3776 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3797 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| OLD | NEW |