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

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

Issue 2894953002: Support inlining of calls where type arguments are passed to generic functions. (Closed)
Patch Set: Merge branch 'master' into slave Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
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
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
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)
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698