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

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: address review comments 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
« no previous file with comments | « runtime/vm/flow_graph_allocator.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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
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
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
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
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
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
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)
OLDNEW
« no previous file with comments | « runtime/vm/flow_graph_allocator.cc ('k') | runtime/vm/flow_graph_type_propagator.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698