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) { | |
|
Vyacheslav Egorov (Google)
2017/07/06 10:31:57
Maybe this case needs to be kept in CallSiteInline
regis
2017/07/06 19:03:25
If I keep CallSiteInliner::InlineCall(), it is not
| |
| 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 Definition* defn = NULL; | |
| 553 if (is_polymorphic && (i == first_param_index)) { | |
| 554 // Replace the receiver argument with a redefinition to prevent code from | |
| 555 // the inlined body from being hoisted above the inlined entry. | |
| 556 RedefinitionInstr* redefinition = | |
| 557 new (zone) RedefinitionInstr(actual->Copy(zone)); | |
| 558 redefinition->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index()); | |
| 559 if (target_info->IsSingleCid()) { | |
| 560 redefinition->UpdateType(CompileType::FromCid(target_info->cid_start)); | |
| 561 } | |
| 562 redefinition->InsertAfter(callee_entry); | |
| 563 defn = redefinition; | |
| 564 } else if (actual != NULL) { | |
| 565 defn = actual->definition(); | |
| 566 } | |
| 567 if (defn != NULL) { | |
| 568 call_data->parameter_stubs->At(first_arg_stub_index + i) | |
| 569 ->ReplaceUsesWith(defn); | |
| 570 } | |
| 571 } | |
| 572 | |
| 573 if (!is_polymorphic) { | |
| 574 // Remove push arguments of the call. | |
| 575 Definition* call = call_data->call; | |
| 576 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 577 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 578 push->ReplaceUsesWith(push->value()->definition()); | |
| 579 push->RemoveFromGraph(); | |
| 580 } | |
| 581 } | |
| 582 | |
| 583 // Replace remaining constants with uses by constants in the caller's | |
| 584 // initial definitions. | |
| 585 GrowableArray<Definition*>* defns = | |
| 586 callee_graph->graph_entry()->initial_definitions(); | |
| 587 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 588 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 589 if ((constant != NULL) && constant->HasUses()) { | |
| 590 constant->ReplaceUsesWith(caller_graph->GetConstant(constant->value())); | |
| 591 } | |
| 592 SpecialParameterInstr* param = (*defns)[i]->AsSpecialParameter(); | |
| 593 if ((param != NULL) && param->HasUses()) { | |
| 594 if (param->kind() == SpecialParameterInstr::kContext) { | |
| 595 ASSERT(!is_polymorphic); | |
| 596 // We do not support polymorphic inlining of closure calls (we did when | |
| 597 // there was a class per closure). | |
| 598 ASSERT(call_data->call->IsClosureCall()); | |
| 599 LoadFieldInstr* context_load = new (zone) LoadFieldInstr( | |
| 600 new Value((*arguments)[first_param_index]->definition()), | |
| 601 Closure::context_offset(), | |
| 602 AbstractType::ZoneHandle(zone, AbstractType::null()), | |
| 603 call_data->call->token_pos()); | |
| 604 context_load->set_is_immutable(true); | |
| 605 context_load->set_ssa_temp_index(caller_graph->alloc_ssa_temp_index()); | |
| 606 context_load->InsertBefore(callee_entry->next()); | |
| 607 param->ReplaceUsesWith(context_load); | |
| 608 } else { | |
| 609 ASSERT(param->kind() == SpecialParameterInstr::kTypeArgs); | |
| 610 Definition* type_args; | |
| 611 if (first_param_index > 0) { | |
| 612 type_args = (*arguments)[0]->definition(); | |
| 613 } else { | |
| 614 type_args = callee_graph->constant_null(); | |
| 615 } | |
| 616 param->ReplaceUsesWith(type_args); | |
| 617 } | |
| 618 } | |
| 619 } | |
| 620 | |
| 621 // Check that inlining maintains use lists. | |
| 622 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph->VerifyUseLists()); | |
| 623 } | |
| 624 | |
| 625 | |
| 517 class CallSiteInliner : public ValueObject { | 626 class CallSiteInliner : public ValueObject { |
| 518 public: | 627 public: |
| 519 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) | 628 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) |
| 520 : inliner_(inliner), | 629 : inliner_(inliner), |
| 521 caller_graph_(inliner->flow_graph()), | 630 caller_graph_(inliner->flow_graph()), |
| 522 inlined_(false), | 631 inlined_(false), |
| 523 initial_size_(inliner->flow_graph()->InstructionCount()), | 632 initial_size_(inliner->flow_graph()->InstructionCount()), |
| 524 inlined_size_(0), | 633 inlined_size_(0), |
| 525 inlined_recursive_call_(false), | 634 inlined_recursive_call_(false), |
| 526 inlining_depth_(1), | 635 inlining_depth_(1), |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 return true; | 675 return true; |
| 567 } | 676 } |
| 568 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 677 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 569 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { | 678 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { |
| 570 return true; | 679 return true; |
| 571 } | 680 } |
| 572 return false; | 681 return false; |
| 573 } | 682 } |
| 574 | 683 |
| 575 void InlineCalls() { | 684 void InlineCalls() { |
| 576 // If inlining depth is less then one abort. | 685 // If inlining depth is less than one abort. |
| 577 if (inlining_depth_threshold_ < 1) return; | 686 if (inlining_depth_threshold_ < 1) return; |
| 578 if (caller_graph_->function().deoptimization_counter() >= | 687 if (caller_graph_->function().deoptimization_counter() >= |
| 579 FLAG_deoptimization_counter_inlining_threshold) { | 688 FLAG_deoptimization_counter_inlining_threshold) { |
| 580 return; | 689 return; |
| 581 } | 690 } |
| 582 // Create two call site collections to swap between. | 691 // Create two call site collections to swap between. |
| 583 CallSites sites1(caller_graph_, inlining_depth_threshold_); | 692 CallSites sites1(caller_graph_, inlining_depth_threshold_); |
| 584 CallSites sites2(caller_graph_, inlining_depth_threshold_); | 693 CallSites sites2(caller_graph_, inlining_depth_threshold_); |
| 585 CallSites* call_sites_temp = NULL; | 694 CallSites* call_sites_temp = NULL; |
| 586 collected_call_sites_ = &sites1; | 695 collected_call_sites_ = &sites1; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 822 inliner_->precompiler_->TryApplyFeedback( | 931 inliner_->precompiler_->TryApplyFeedback( |
| 823 parsed_function->function(), callee_graph); | 932 parsed_function->function(), callee_graph); |
| 824 } | 933 } |
| 825 } | 934 } |
| 826 #endif | 935 #endif |
| 827 | 936 |
| 828 // The parameter stubs are a copy of the actual arguments providing | 937 // The parameter stubs are a copy of the actual arguments providing |
| 829 // concrete information about the values, for example constant values, | 938 // concrete information about the values, for example constant values, |
| 830 // without linking between the caller and callee graphs. | 939 // without linking between the caller and callee graphs. |
| 831 // TODO(zerny): Put more information in the stubs, eg, type information. | 940 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 941 const intptr_t first_actual_param_index = call_data->first_param_index; | |
| 942 const intptr_t inlined_type_args_param = | |
| 943 (FLAG_reify_generic_functions && function.IsGeneric()) ? 1 : 0; | |
| 944 const intptr_t num_inlined_params = | |
| 945 inlined_type_args_param + function.NumParameters(); | |
| 832 ZoneGrowableArray<Definition*>* param_stubs = | 946 ZoneGrowableArray<Definition*>* param_stubs = |
| 833 new (Z) ZoneGrowableArray<Definition*>(function.NumParameters()); | 947 new (Z) ZoneGrowableArray<Definition*>(num_inlined_params); |
| 834 | 948 |
| 949 // Create a ConstantInstr as Definition for the type arguments, if any. | |
| 950 if (first_actual_param_index > 0) { | |
| 951 // A type argument vector is explicitly passed. | |
| 952 param_stubs->Add( | |
| 953 CreateParameterStub(-1, (*arguments)[0], callee_graph)); | |
| 954 } else if (inlined_type_args_param > 0) { | |
| 955 // No type argument vector is passed to the generic function, | |
| 956 // pass a null vector, which is the same as a vector of dynamic types. | |
| 957 param_stubs->Add(callee_graph->GetConstant(Object::ZoneHandle())); | |
| 958 } | |
| 835 // Create a parameter stub for each fixed positional parameter. | 959 // Create a parameter stub for each fixed positional parameter. |
| 836 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 960 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 837 param_stubs->Add( | 961 param_stubs->Add(CreateParameterStub( |
| 838 CreateParameterStub(i, (*arguments)[i], callee_graph)); | 962 i, (*arguments)[first_actual_param_index + i], callee_graph)); |
| 839 } | 963 } |
| 840 | 964 |
| 841 // If the callee has optional parameters, rebuild the argument and stub | 965 // 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 | 966 // arrays so that actual arguments are in one-to-one with the formal |
| 843 // parameters. | 967 // parameters. |
| 844 if (function.HasOptionalParameters()) { | 968 if (function.HasOptionalParameters()) { |
| 845 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); | 969 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); |
| 846 if (!AdjustForOptionalParameters(*parsed_function, argument_names, | 970 if (!AdjustForOptionalParameters( |
| 847 arguments, param_stubs, | 971 *parsed_function, first_actual_param_index, argument_names, |
| 848 callee_graph)) { | 972 arguments, param_stubs, callee_graph)) { |
| 849 function.set_is_inlinable(false); | 973 function.set_is_inlinable(false); |
| 850 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); | 974 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); |
| 851 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, | 975 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, |
| 852 &function, call_data->call); | 976 &function, call_data->call); |
| 853 return false; | 977 return false; |
| 854 } | 978 } |
| 855 } | 979 } |
| 856 | 980 |
| 857 // After treating optional parameters the actual/formal count must | 981 // After treating optional parameters the actual/formal count must |
| 858 // match. | 982 // match. |
| 859 // TODO(regis): Consider type arguments in arguments. | 983 ASSERT(arguments->length() == |
| 860 if (arguments->length() != function.NumParameters()) { | 984 first_actual_param_index + function.NumParameters()); |
| 861 ASSERT(function.IsGeneric()); | 985 ASSERT(param_stubs->length() == |
| 862 ASSERT(arguments->length() == function.NumParameters() + 1); | 986 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 | 987 |
| 871 // Update try-index of the callee graph. | 988 // Update try-index of the callee graph. |
| 872 BlockEntryInstr* call_block = call_data->call->GetBlock(); | 989 BlockEntryInstr* call_block = call_data->call->GetBlock(); |
| 873 if (call_block->InsideTryBlock()) { | 990 if (call_block->InsideTryBlock()) { |
| 874 intptr_t try_index = call_block->try_index(); | 991 intptr_t try_index = call_block->try_index(); |
| 875 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); | 992 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); |
| 876 !it.Done(); it.Advance()) { | 993 !it.Done(); it.Advance()) { |
| 877 BlockEntryInstr* block = it.Current(); | 994 BlockEntryInstr* block = it.Current(); |
| 878 block->set_try_index(try_index); | 995 block->set_try_index(try_index); |
| 879 } | 996 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 } | 1130 } |
| 1014 // When inlined, we add the deferred prefixes of the callee to the | 1131 // When inlined, we add the deferred prefixes of the callee to the |
| 1015 // caller's list of deferred prefixes. | 1132 // caller's list of deferred prefixes. |
| 1016 caller_graph()->AddToDeferredPrefixes( | 1133 caller_graph()->AddToDeferredPrefixes( |
| 1017 callee_graph->deferred_prefixes()); | 1134 callee_graph->deferred_prefixes()); |
| 1018 | 1135 |
| 1019 FlowGraphInliner::SetInliningId( | 1136 FlowGraphInliner::SetInliningId( |
| 1020 callee_graph, | 1137 callee_graph, |
| 1021 inliner_->NextInlineId(callee_graph->function(), | 1138 inliner_->NextInlineId(callee_graph->function(), |
| 1022 call_data->call->token_pos(), | 1139 call_data->call->token_pos(), |
| 1023 call_data->caller_inlining_id_)); | 1140 call_data->caller_inlining_id)); |
| 1024 TRACE_INLINING(THR_Print(" Success\n")); | 1141 TRACE_INLINING(THR_Print(" Success\n")); |
| 1025 TRACE_INLINING(THR_Print(" with size %" Pd "\n", | 1142 TRACE_INLINING(THR_Print(" with size %" Pd "\n", |
| 1026 function.optimized_instruction_count())); | 1143 function.optimized_instruction_count())); |
| 1027 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); | 1144 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); |
| 1028 return true; | 1145 return true; |
| 1029 } else { | 1146 } else { |
| 1030 error = thread()->sticky_error(); | 1147 error = thread()->sticky_error(); |
| 1031 thread()->clear_sticky_error(); | 1148 thread()->clear_sticky_error(); |
| 1032 | 1149 |
| 1033 if (error.IsLanguageError() && | 1150 if (error.IsLanguageError() && |
| (...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1114 for (int t = 0; t < depth; t++) { | 1231 for (int t = 0; t < depth; t++) { |
| 1115 THR_Print(" "); | 1232 THR_Print(" "); |
| 1116 } | 1233 } |
| 1117 THR_Print("NO %" Pd " %s - %s\n", info.call_instr->GetDeoptId(), | 1234 THR_Print("NO %" Pd " %s - %s\n", info.call_instr->GetDeoptId(), |
| 1118 info.inlined->ToQualifiedCString(), info.bailout_reason); | 1235 info.inlined->ToQualifiedCString(), info.bailout_reason); |
| 1119 call_instructions_printed.Add(info.call_instr->GetDeoptId()); | 1236 call_instructions_printed.Add(info.call_instr->GetDeoptId()); |
| 1120 } | 1237 } |
| 1121 } | 1238 } |
| 1122 } | 1239 } |
| 1123 | 1240 |
| 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) { | 1241 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { |
| 1180 intptr_t count = 0; | 1242 intptr_t count = 0; |
| 1181 for (intptr_t i = 0; i < arguments.length(); i++) { | 1243 for (intptr_t i = 0; i < arguments.length(); i++) { |
| 1182 if (arguments[i]->BindsToConstant()) count++; | 1244 if (arguments[i]->BindsToConstant()) count++; |
| 1183 } | 1245 } |
| 1184 return count; | 1246 return count; |
| 1185 } | 1247 } |
| 1186 | 1248 |
| 1187 // Parse a function reusing the cache if possible. | 1249 // Parse a function reusing the cache if possible. |
| 1188 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 1250 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1221 } | 1283 } |
| 1222 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), | 1284 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), |
| 1223 &call->function(), call); | 1285 &call->function(), call); |
| 1224 continue; | 1286 continue; |
| 1225 } | 1287 } |
| 1226 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1288 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1227 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1289 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1228 arguments.Add(call->PushArgumentAt(i)->value()); | 1290 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1229 } | 1291 } |
| 1230 InlinedCallData call_data( | 1292 InlinedCallData call_data( |
| 1231 call, &arguments, call_info[call_idx].caller(), | 1293 call, call->FirstParamIndex(), &arguments, |
| 1294 call_info[call_idx].caller(), | |
| 1232 call_info[call_idx].caller_graph->inlining_id()); | 1295 call_info[call_idx].caller_graph->inlining_id()); |
| 1233 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1296 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 1234 InlineCall(&call_data); | 1297 InlineCall(zone(), caller_graph_, &call_data, NULL); |
| 1235 } | 1298 } |
| 1236 } | 1299 } |
| 1237 } | 1300 } |
| 1238 | 1301 |
| 1239 void InlineClosureCalls() { | 1302 void InlineClosureCalls() { |
| 1240 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1303 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
| 1241 inlining_call_sites_->closure_calls(); | 1304 inlining_call_sites_->closure_calls(); |
| 1242 TRACE_INLINING( | 1305 TRACE_INLINING( |
| 1243 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); | 1306 THR_Print(" Closure Calls (%" Pd ")\n", call_info.length())); |
| 1244 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1307 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()) { | 1330 call->ArgumentCount() < target.num_fixed_parameters()) { |
| 1268 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); | 1331 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); |
| 1269 continue; | 1332 continue; |
| 1270 } | 1333 } |
| 1271 | 1334 |
| 1272 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1335 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1273 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1336 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1274 arguments.Add(call->PushArgumentAt(i)->value()); | 1337 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1275 } | 1338 } |
| 1276 InlinedCallData call_data( | 1339 InlinedCallData call_data( |
| 1277 call, &arguments, call_info[call_idx].caller(), | 1340 call, call->FirstParamIndex(), &arguments, |
| 1341 call_info[call_idx].caller(), | |
| 1278 call_info[call_idx].caller_graph->inlining_id()); | 1342 call_info[call_idx].caller_graph->inlining_id()); |
| 1279 if (TryInlining(target, call->argument_names(), &call_data)) { | 1343 if (TryInlining(target, call->argument_names(), &call_data)) { |
| 1280 InlineCall(&call_data); | 1344 InlineCall(zone(), caller_graph_, &call_data, NULL); |
| 1281 } | 1345 } |
| 1282 } | 1346 } |
| 1283 } | 1347 } |
| 1284 | 1348 |
| 1285 void InlineInstanceCalls() { | 1349 void InlineInstanceCalls() { |
| 1286 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1350 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
| 1287 inlining_call_sites_->instance_calls(); | 1351 inlining_call_sites_->instance_calls(); |
| 1288 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", | 1352 TRACE_INLINING(THR_Print(" Polymorphic Instance Calls (%" Pd ")\n", |
| 1289 call_info.length())); | 1353 call_info.length())); |
| 1290 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { | 1354 for (intptr_t call_idx = 0; call_idx < call_info.length(); ++call_idx) { |
| 1291 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; | 1355 PolymorphicInstanceCallInstr* call = call_info[call_idx].call; |
| 1292 // PolymorphicInliner introduces deoptimization paths. | 1356 // PolymorphicInliner introduces deoptimization paths. |
| 1293 if (!call->complete() && !FLAG_polymorphic_with_deopt) { | 1357 if (!call->complete() && !FLAG_polymorphic_with_deopt) { |
| 1294 TRACE_INLINING( | 1358 TRACE_INLINING( |
| 1295 THR_Print(" => %s\n Bailout: call with checks\n", | 1359 THR_Print(" => %s\n Bailout: call with checks\n", |
| 1296 call->instance_call()->function_name().ToCString())); | 1360 call->instance_call()->function_name().ToCString())); |
| 1297 continue; | 1361 continue; |
| 1298 } | 1362 } |
| 1299 const Function& cl = call_info[call_idx].caller(); | 1363 const Function& cl = call_info[call_idx].caller(); |
| 1300 intptr_t caller_inlining_id = | 1364 intptr_t caller_inlining_id = |
| 1301 call_info[call_idx].caller_graph->inlining_id(); | 1365 call_info[call_idx].caller_graph->inlining_id(); |
| 1302 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1366 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
| 1303 inliner.Inline(); | 1367 inliner.Inline(); |
| 1304 } | 1368 } |
| 1305 } | 1369 } |
| 1306 | 1370 |
| 1307 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, | 1371 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, |
| 1372 intptr_t first_param_index, | |
| 1308 const Array& argument_names, | 1373 const Array& argument_names, |
| 1309 GrowableArray<Value*>* arguments, | 1374 GrowableArray<Value*>* arguments, |
| 1310 ZoneGrowableArray<Definition*>* param_stubs, | 1375 ZoneGrowableArray<Definition*>* param_stubs, |
| 1311 FlowGraph* callee_graph) { | 1376 FlowGraph* callee_graph) { |
| 1312 const Function& function = parsed_function.function(); | 1377 const Function& function = parsed_function.function(); |
| 1313 // The language and this code does not support both optional positional | 1378 // The language and this code does not support both optional positional |
| 1314 // and optional named parameters for the same function. | 1379 // and optional named parameters for the same function. |
| 1315 ASSERT(!function.HasOptionalPositionalParameters() || | 1380 ASSERT(!function.HasOptionalPositionalParameters() || |
| 1316 !function.HasOptionalNamedParameters()); | 1381 !function.HasOptionalNamedParameters()); |
| 1317 | 1382 |
| 1318 // TODO(regis): Consider type arguments in arguments. | |
| 1319 intptr_t arg_count = arguments->length(); | 1383 intptr_t arg_count = arguments->length(); |
| 1320 intptr_t param_count = function.NumParameters(); | 1384 intptr_t param_count = function.NumParameters(); |
| 1321 intptr_t fixed_param_count = function.num_fixed_parameters(); | 1385 intptr_t fixed_param_count = function.num_fixed_parameters(); |
| 1322 ASSERT(fixed_param_count <= arg_count); | 1386 ASSERT(fixed_param_count <= arg_count - first_param_index); |
| 1323 ASSERT(arg_count <= param_count); | 1387 ASSERT(arg_count - first_param_index <= param_count); |
| 1324 | 1388 |
| 1325 if (function.HasOptionalPositionalParameters()) { | 1389 if (function.HasOptionalPositionalParameters()) { |
| 1326 // Create a stub for each optional positional parameters with an actual. | 1390 // Create a stub for each optional positional parameters with an actual. |
| 1327 for (intptr_t i = fixed_param_count; i < arg_count; ++i) { | 1391 for (intptr_t i = first_param_index + fixed_param_count; i < arg_count; |
| 1392 ++i) { | |
| 1328 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 1393 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 1329 } | 1394 } |
| 1330 ASSERT(function.NumOptionalPositionalParameters() == | 1395 ASSERT(function.NumOptionalPositionalParameters() == |
| 1331 (param_count - fixed_param_count)); | 1396 (param_count - fixed_param_count)); |
| 1332 // For each optional positional parameter without an actual, add its | 1397 // For each optional positional parameter without an actual, add its |
| 1333 // default value. | 1398 // default value. |
| 1334 for (intptr_t i = arg_count; i < param_count; ++i) { | 1399 for (intptr_t i = arg_count - first_param_index; i < param_count; ++i) { |
| 1335 const Instance& object = | 1400 const Instance& object = |
| 1336 parsed_function.DefaultParameterValueAt(i - fixed_param_count); | 1401 parsed_function.DefaultParameterValueAt(i - fixed_param_count); |
| 1337 ConstantInstr* constant = new (Z) ConstantInstr(object); | 1402 ConstantInstr* constant = new (Z) ConstantInstr(object); |
| 1338 arguments->Add(NULL); | 1403 arguments->Add(NULL); |
| 1339 param_stubs->Add(constant); | 1404 param_stubs->Add(constant); |
| 1340 } | 1405 } |
| 1341 return true; | 1406 return true; |
| 1342 } | 1407 } |
| 1343 | 1408 |
| 1344 ASSERT(function.HasOptionalNamedParameters()); | 1409 ASSERT(function.HasOptionalNamedParameters()); |
| 1345 | 1410 |
| 1346 // Passed arguments must match fixed parameters plus named arguments. | 1411 // Passed arguments (not counting optional type args) must match fixed |
| 1412 // parameters plus named arguments. | |
| 1347 intptr_t argument_names_count = | 1413 intptr_t argument_names_count = |
| 1348 (argument_names.IsNull()) ? 0 : argument_names.Length(); | 1414 (argument_names.IsNull()) ? 0 : argument_names.Length(); |
| 1349 ASSERT(arg_count == (fixed_param_count + argument_names_count)); | 1415 ASSERT((arg_count - first_param_index) == |
| 1416 (fixed_param_count + argument_names_count)); | |
| 1350 | 1417 |
| 1351 // Fast path when no optional named parameters are given. | 1418 // Fast path when no optional named parameters are given. |
| 1352 if (argument_names_count == 0) { | 1419 if (argument_names_count == 0) { |
| 1353 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { | 1420 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { |
| 1354 arguments->Add(NULL); | 1421 arguments->Add(NULL); |
| 1355 param_stubs->Add(GetDefaultValue(i, parsed_function)); | 1422 param_stubs->Add(GetDefaultValue(i, parsed_function)); |
| 1356 } | 1423 } |
| 1357 return true; | 1424 return true; |
| 1358 } | 1425 } |
| 1359 | 1426 |
| 1360 // Otherwise, build a collection of name/argument pairs. | 1427 // Otherwise, build a collection of name/argument pairs. |
| 1361 GrowableArray<NamedArgument> named_args(argument_names_count); | 1428 GrowableArray<NamedArgument> named_args(argument_names_count); |
| 1362 for (intptr_t i = 0; i < argument_names.Length(); ++i) { | 1429 for (intptr_t i = 0; i < argument_names.Length(); ++i) { |
| 1363 String& arg_name = String::Handle(caller_graph_->zone()); | 1430 String& arg_name = String::Handle(caller_graph_->zone()); |
| 1364 arg_name ^= argument_names.At(i); | 1431 arg_name ^= argument_names.At(i); |
| 1365 named_args.Add( | 1432 named_args.Add(NamedArgument( |
| 1366 NamedArgument(&arg_name, (*arguments)[i + fixed_param_count])); | 1433 &arg_name, (*arguments)[first_param_index + fixed_param_count + i])); |
| 1367 } | 1434 } |
| 1368 | 1435 |
| 1369 // Truncate the arguments array to just fixed parameters. | 1436 // Truncate the arguments array to just type args and fixed parameters. |
| 1370 arguments->TruncateTo(fixed_param_count); | 1437 arguments->TruncateTo(first_param_index + fixed_param_count); |
| 1371 | 1438 |
| 1372 // For each optional named parameter, add the actual argument or its | 1439 // For each optional named parameter, add the actual argument or its |
| 1373 // default if no argument is passed. | 1440 // default if no argument is passed. |
| 1374 intptr_t match_count = 0; | 1441 intptr_t match_count = 0; |
| 1375 for (intptr_t i = fixed_param_count; i < param_count; ++i) { | 1442 for (intptr_t i = fixed_param_count; i < param_count; ++i) { |
| 1376 String& param_name = String::Handle(function.ParameterNameAt(i)); | 1443 String& param_name = String::Handle(function.ParameterNameAt(i)); |
| 1377 // Search for and add the named argument. | 1444 // Search for and add the named argument. |
| 1378 Value* arg = NULL; | 1445 Value* arg = NULL; |
| 1379 for (intptr_t j = 0; j < named_args.length(); ++j) { | 1446 for (intptr_t j = 0; j < named_args.length(); ++j) { |
| 1380 if (param_name.Equals(*named_args[j].name)) { | 1447 if (param_name.Equals(*named_args[j].name)) { |
| 1381 arg = named_args[j].value; | 1448 arg = named_args[j].value; |
| 1382 match_count++; | 1449 match_count++; |
| 1383 break; | 1450 break; |
| 1384 } | 1451 } |
| 1385 } | 1452 } |
| 1386 arguments->Add(arg); | 1453 arguments->Add(arg); |
| 1387 // Create a stub for the argument or use the parameter's default value. | 1454 // Create a stub for the argument or use the parameter's default value. |
| 1388 if (arg != NULL) { | 1455 if (arg != NULL) { |
| 1389 param_stubs->Add(CreateParameterStub(i, arg, callee_graph)); | 1456 param_stubs->Add( |
| 1457 CreateParameterStub(first_param_index + i, arg, callee_graph)); | |
| 1390 } else { | 1458 } else { |
| 1391 param_stubs->Add( | 1459 param_stubs->Add( |
| 1392 GetDefaultValue(i - fixed_param_count, parsed_function)); | 1460 GetDefaultValue(i - fixed_param_count, parsed_function)); |
| 1393 } | 1461 } |
| 1394 } | 1462 } |
| 1395 return argument_names_count == match_count; | 1463 return argument_names_count == match_count; |
| 1396 } | 1464 } |
| 1397 | 1465 |
| 1398 FlowGraphInliner* inliner_; | 1466 FlowGraphInliner* inliner_; |
| 1399 FlowGraph* caller_graph_; | 1467 FlowGraph* caller_graph_; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 target_info.IsSingleCid() && | 1590 target_info.IsSingleCid() && |
| 1523 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { | 1591 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
| 1524 owner_->inlined_ = true; | 1592 owner_->inlined_ = true; |
| 1525 return true; | 1593 return true; |
| 1526 } | 1594 } |
| 1527 | 1595 |
| 1528 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1596 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
| 1529 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1597 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
| 1530 arguments.Add(call_->PushArgumentAt(i)->value()); | 1598 arguments.Add(call_->PushArgumentAt(i)->value()); |
| 1531 } | 1599 } |
| 1532 InlinedCallData call_data(call_, &arguments, caller_function_, | 1600 InlinedCallData call_data(call_, call_->instance_call()->FirstParamIndex(), |
| 1533 caller_inlining_id_); | 1601 &arguments, caller_function_, caller_inlining_id_); |
| 1534 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); | 1602 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); |
| 1535 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), | 1603 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
| 1536 &call_data)) { | 1604 &call_data)) { |
| 1537 return false; | 1605 return false; |
| 1538 } | 1606 } |
| 1539 | 1607 |
| 1540 FlowGraph* callee_graph = call_data.callee_graph; | 1608 FlowGraph* callee_graph = call_data.callee_graph; |
| 1541 call_data.exit_collector->PrepareGraphs(callee_graph); | 1609 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1542 inlined_entries_.Add(callee_graph->graph_entry()); | 1610 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1543 exit_collector_->Union(call_data.exit_collector); | 1611 exit_collector_->Union(call_data.exit_collector); |
| 1544 | 1612 |
| 1545 // Replace parameter stubs and constants. Replace the receiver argument | 1613 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; | 1614 return true; |
| 1590 } | 1615 } |
| 1591 | 1616 |
| 1592 | 1617 |
| 1593 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { | 1618 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { |
| 1594 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1619 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
| 1595 Value* input = second->InputAt(i); | 1620 Value* input = second->InputAt(i); |
| 1596 input->definition()->AddInputUse(input); | 1621 input->definition()->AddInputUse(input); |
| 1597 } | 1622 } |
| 1598 first->LinkTo(second); | 1623 first->LinkTo(second); |
| (...skipping 2168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3767 } | 3792 } |
| 3768 | 3793 |
| 3769 default: | 3794 default: |
| 3770 return false; | 3795 return false; |
| 3771 } | 3796 } |
| 3772 } | 3797 } |
| 3773 | 3798 |
| 3774 | 3799 |
| 3775 } // namespace dart | 3800 } // namespace dart |
| 3776 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3801 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| OLD | NEW |