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 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 566 return true; | 569 return true; |
| 567 } | 570 } |
| 568 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 571 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 569 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { | 572 (instr_count <= FLAG_inlining_constant_arguments_min_size_threshold)) { |
| 570 return true; | 573 return true; |
| 571 } | 574 } |
| 572 return false; | 575 return false; |
| 573 } | 576 } |
| 574 | 577 |
| 575 void InlineCalls() { | 578 void InlineCalls() { |
| 576 // If inlining depth is less then one abort. | 579 // If inlining depth is less than one abort. |
| 577 if (inlining_depth_threshold_ < 1) return; | 580 if (inlining_depth_threshold_ < 1) return; |
| 578 if (caller_graph_->function().deoptimization_counter() >= | 581 if (caller_graph_->function().deoptimization_counter() >= |
| 579 FLAG_deoptimization_counter_inlining_threshold) { | 582 FLAG_deoptimization_counter_inlining_threshold) { |
| 580 return; | 583 return; |
| 581 } | 584 } |
| 582 // Create two call site collections to swap between. | 585 // Create two call site collections to swap between. |
| 583 CallSites sites1(caller_graph_, inlining_depth_threshold_); | 586 CallSites sites1(caller_graph_, inlining_depth_threshold_); |
| 584 CallSites sites2(caller_graph_, inlining_depth_threshold_); | 587 CallSites sites2(caller_graph_, inlining_depth_threshold_); |
| 585 CallSites* call_sites_temp = NULL; | 588 CallSites* call_sites_temp = NULL; |
| 586 collected_call_sites_ = &sites1; | 589 collected_call_sites_ = &sites1; |
| (...skipping 235 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 822 inliner_->precompiler_->TryApplyFeedback( | 825 inliner_->precompiler_->TryApplyFeedback( |
| 823 parsed_function->function(), callee_graph); | 826 parsed_function->function(), callee_graph); |
| 824 } | 827 } |
| 825 } | 828 } |
| 826 #endif | 829 #endif |
| 827 | 830 |
| 828 // The parameter stubs are a copy of the actual arguments providing | 831 // The parameter stubs are a copy of the actual arguments providing |
| 829 // concrete information about the values, for example constant values, | 832 // concrete information about the values, for example constant values, |
| 830 // without linking between the caller and callee graphs. | 833 // without linking between the caller and callee graphs. |
| 831 // TODO(zerny): Put more information in the stubs, eg, type information. | 834 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 835 const intptr_t first_actual_param_index = call_data->first_param_index; | |
| 836 const intptr_t inlined_type_args_param = | |
| 837 (FLAG_reify_generic_functions && function.IsGeneric()) ? 1 : 0; | |
| 838 const intptr_t num_inlined_params = | |
| 839 inlined_type_args_param + function.NumParameters(); | |
| 832 ZoneGrowableArray<Definition*>* param_stubs = | 840 ZoneGrowableArray<Definition*>* param_stubs = |
| 833 new (Z) ZoneGrowableArray<Definition*>(function.NumParameters()); | 841 new (Z) ZoneGrowableArray<Definition*>(num_inlined_params); |
| 834 | 842 |
| 843 // Create a ConstantInstr as Definition for the type arguments, if any. | |
| 844 if (first_actual_param_index > 0) { | |
| 845 // A type argument vector is explicitly passed. | |
| 846 param_stubs->Add( | |
| 847 CreateParameterStub(-1, (*arguments)[0], callee_graph)); | |
| 848 } else if (inlined_type_args_param > 0) { | |
| 849 // No type argument vector is passed to the generic function, | |
| 850 // pass a null vector, which is the same as a vector of dynamic types. | |
| 851 param_stubs->Add(callee_graph->GetConstant(Object::ZoneHandle())); | |
| 852 } | |
| 835 // Create a parameter stub for each fixed positional parameter. | 853 // Create a parameter stub for each fixed positional parameter. |
| 836 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 854 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 837 param_stubs->Add( | 855 param_stubs->Add(CreateParameterStub( |
| 838 CreateParameterStub(i, (*arguments)[i], callee_graph)); | 856 i, (*arguments)[first_actual_param_index + i], callee_graph)); |
| 839 } | 857 } |
| 840 | 858 |
| 841 // If the callee has optional parameters, rebuild the argument and stub | 859 // 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 | 860 // arrays so that actual arguments are in one-to-one with the formal |
| 843 // parameters. | 861 // parameters. |
| 844 if (function.HasOptionalParameters()) { | 862 if (function.HasOptionalParameters()) { |
| 845 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); | 863 TRACE_INLINING(THR_Print(" adjusting for optional parameters\n")); |
| 846 if (!AdjustForOptionalParameters(*parsed_function, argument_names, | 864 if (!AdjustForOptionalParameters( |
| 847 arguments, param_stubs, | 865 *parsed_function, first_actual_param_index, argument_names, |
| 848 callee_graph)) { | 866 arguments, param_stubs, callee_graph)) { |
| 849 function.set_is_inlinable(false); | 867 function.set_is_inlinable(false); |
| 850 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); | 868 TRACE_INLINING(THR_Print(" Bailout: optional arg mismatch\n")); |
| 851 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, | 869 PRINT_INLINING_TREE("Optional arg mismatch", &call_data->caller, |
| 852 &function, call_data->call); | 870 &function, call_data->call); |
| 853 return false; | 871 return false; |
| 854 } | 872 } |
| 855 } | 873 } |
| 856 | 874 |
| 857 // After treating optional parameters the actual/formal count must | 875 // After treating optional parameters the actual/formal count must |
| 858 // match. | 876 // match. |
| 859 // TODO(regis): Consider type arguments in arguments. | 877 ASSERT(arguments->length() == |
| 860 if (arguments->length() != function.NumParameters()) { | 878 first_actual_param_index + function.NumParameters()); |
| 861 ASSERT(function.IsGeneric()); | 879 ASSERT(param_stubs->length() == |
| 862 ASSERT(arguments->length() == function.NumParameters() + 1); | 880 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 | 881 |
| 871 // Update try-index of the callee graph. | 882 // Update try-index of the callee graph. |
| 872 BlockEntryInstr* call_block = call_data->call->GetBlock(); | 883 BlockEntryInstr* call_block = call_data->call->GetBlock(); |
| 873 if (call_block->InsideTryBlock()) { | 884 if (call_block->InsideTryBlock()) { |
| 874 intptr_t try_index = call_block->try_index(); | 885 intptr_t try_index = call_block->try_index(); |
| 875 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); | 886 for (BlockIterator it = callee_graph->reverse_postorder_iterator(); |
| 876 !it.Done(); it.Advance()) { | 887 !it.Done(); it.Advance()) { |
| 877 BlockEntryInstr* block = it.Current(); | 888 BlockEntryInstr* block = it.Current(); |
| 878 block->set_try_index(try_index); | 889 block->set_try_index(try_index); |
| 879 } | 890 } |
| (...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1013 } | 1024 } |
| 1014 // When inlined, we add the deferred prefixes of the callee to the | 1025 // When inlined, we add the deferred prefixes of the callee to the |
| 1015 // caller's list of deferred prefixes. | 1026 // caller's list of deferred prefixes. |
| 1016 caller_graph()->AddToDeferredPrefixes( | 1027 caller_graph()->AddToDeferredPrefixes( |
| 1017 callee_graph->deferred_prefixes()); | 1028 callee_graph->deferred_prefixes()); |
| 1018 | 1029 |
| 1019 FlowGraphInliner::SetInliningId( | 1030 FlowGraphInliner::SetInliningId( |
| 1020 callee_graph, | 1031 callee_graph, |
| 1021 inliner_->NextInlineId(callee_graph->function(), | 1032 inliner_->NextInlineId(callee_graph->function(), |
| 1022 call_data->call->token_pos(), | 1033 call_data->call->token_pos(), |
| 1023 call_data->caller_inlining_id_)); | 1034 call_data->caller_inlining_id)); |
| 1024 TRACE_INLINING(THR_Print(" Success\n")); | 1035 TRACE_INLINING(THR_Print(" Success\n")); |
| 1025 TRACE_INLINING(THR_Print(" with size %" Pd "\n", | 1036 TRACE_INLINING(THR_Print(" with size %" Pd "\n", |
| 1026 function.optimized_instruction_count())); | 1037 function.optimized_instruction_count())); |
| 1027 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); | 1038 PRINT_INLINING_TREE(NULL, &call_data->caller, &function, call); |
| 1028 return true; | 1039 return true; |
| 1029 } else { | 1040 } else { |
| 1030 error = thread()->sticky_error(); | 1041 error = thread()->sticky_error(); |
| 1031 thread()->clear_sticky_error(); | 1042 thread()->clear_sticky_error(); |
| 1032 | 1043 |
| 1033 if (error.IsLanguageError() && | 1044 if (error.IsLanguageError() && |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1126 FlowGraph* callee_graph = call_data->callee_graph; | 1137 FlowGraph* callee_graph = call_data->callee_graph; |
| 1127 TargetEntryInstr* callee_entry = | 1138 TargetEntryInstr* callee_entry = |
| 1128 callee_graph->graph_entry()->normal_entry(); | 1139 callee_graph->graph_entry()->normal_entry(); |
| 1129 // Plug result in the caller graph. | 1140 // Plug result in the caller graph. |
| 1130 InlineExitCollector* exit_collector = call_data->exit_collector; | 1141 InlineExitCollector* exit_collector = call_data->exit_collector; |
| 1131 exit_collector->PrepareGraphs(callee_graph); | 1142 exit_collector->PrepareGraphs(callee_graph); |
| 1132 exit_collector->ReplaceCall(callee_entry); | 1143 exit_collector->ReplaceCall(callee_entry); |
| 1133 | 1144 |
| 1134 // Replace each stub with the actual argument or the caller's constant. | 1145 // Replace each stub with the actual argument or the caller's constant. |
| 1135 // Nulls denote optional parameters for which no actual was given. | 1146 // Nulls denote optional parameters for which no actual was given. |
| 1147 const intptr_t first_param_index = call_data->first_param_index; | |
| 1148 // When first_param_index > 0, the stub and actual argument processed in the | |
| 1149 // first loop iteration represent a passed-in type argument vector. | |
| 1136 GrowableArray<Value*>* arguments = call_data->arguments; | 1150 GrowableArray<Value*>* arguments = call_data->arguments; |
| 1151 intptr_t first_arg_stub_index = 0; | |
| 1152 if (arguments->length() != call_data->parameter_stubs->length()) { | |
| 1153 ASSERT(arguments->length() == call_data->parameter_stubs->length() - 1); | |
| 1154 ASSERT(first_param_index == 0); | |
| 1155 // The first parameter stub accepts an optional type argument vector, but | |
| 1156 // none was provided in arguments. | |
| 1157 first_arg_stub_index = 1; | |
| 1158 } | |
| 1137 for (intptr_t i = 0; i < arguments->length(); ++i) { | 1159 for (intptr_t i = 0; i < arguments->length(); ++i) { |
| 1138 Definition* stub = (*call_data->parameter_stubs)[i]; | 1160 Definition* stub = |
| 1161 (*call_data->parameter_stubs)[first_arg_stub_index + i]; | |
| 1139 Value* actual = (*arguments)[i]; | 1162 Value* actual = (*arguments)[i]; |
| 1140 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); | 1163 if (actual != NULL) { |
| 1164 stub->ReplaceUsesWith(actual->definition()); | |
| 1165 } | |
| 1141 } | 1166 } |
| 1142 | 1167 |
| 1143 // Remove push arguments of the call. | 1168 // Remove push arguments of the call. |
| 1144 Definition* call = call_data->call; | 1169 Definition* call = call_data->call; |
| 1145 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | 1170 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { |
| 1146 PushArgumentInstr* push = call->PushArgumentAt(i); | 1171 PushArgumentInstr* push = call->PushArgumentAt(i); |
| 1147 push->ReplaceUsesWith(push->value()->definition()); | 1172 push->ReplaceUsesWith(push->value()->definition()); |
| 1148 push->RemoveFromGraph(); | 1173 push->RemoveFromGraph(); |
| 1149 } | 1174 } |
| 1150 | 1175 |
| 1151 // Replace remaining constants with uses by constants in the caller's | 1176 // Replace remaining constants with uses by constants in the caller's |
| 1152 // initial definitions. | 1177 // initial definitions. |
| 1153 GrowableArray<Definition*>* defns = | 1178 GrowableArray<Definition*>* defns = |
| 1154 callee_graph->graph_entry()->initial_definitions(); | 1179 callee_graph->graph_entry()->initial_definitions(); |
| 1155 for (intptr_t i = 0; i < defns->length(); ++i) { | 1180 for (intptr_t i = 0; i < defns->length(); ++i) { |
| 1156 ConstantInstr* constant = (*defns)[i]->AsConstant(); | 1181 ConstantInstr* constant = (*defns)[i]->AsConstant(); |
| 1157 if ((constant != NULL) && constant->HasUses()) { | 1182 if ((constant != NULL) && constant->HasUses()) { |
| 1158 constant->ReplaceUsesWith( | 1183 constant->ReplaceUsesWith( |
| 1159 caller_graph_->GetConstant(constant->value())); | 1184 caller_graph_->GetConstant(constant->value())); |
| 1160 } | 1185 } |
| 1161 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | 1186 SpecialParameterInstr* param = (*defns)[i]->AsSpecialParameter(); |
| 1162 if ((context != NULL) && context->HasUses()) { | 1187 if ((param != NULL) && param->HasUses()) { |
| 1163 ASSERT(call->IsClosureCall()); | 1188 if (param->kind() == SpecialParameterInstr::kContext) { |
| 1164 LoadFieldInstr* context_load = new (Z) LoadFieldInstr( | 1189 ASSERT(call->IsClosureCall()); |
| 1165 new Value((*arguments)[0]->definition()), Closure::context_offset(), | 1190 LoadFieldInstr* context_load = new (Z) LoadFieldInstr( |
| 1166 AbstractType::ZoneHandle(zone(), AbstractType::null()), | 1191 new Value((*arguments)[first_param_index]->definition()), |
| 1167 call_data->call->token_pos()); | 1192 Closure::context_offset(), |
| 1168 context_load->set_is_immutable(true); | 1193 AbstractType::ZoneHandle(zone(), AbstractType::null()), |
| 1169 context_load->set_ssa_temp_index(caller_graph_->alloc_ssa_temp_index()); | 1194 call_data->call->token_pos()); |
| 1170 context_load->InsertBefore(callee_entry->next()); | 1195 context_load->set_is_immutable(true); |
| 1171 context->ReplaceUsesWith(context_load); | 1196 context_load->set_ssa_temp_index( |
| 1197 caller_graph_->alloc_ssa_temp_index()); | |
| 1198 context_load->InsertBefore(callee_entry->next()); | |
| 1199 param->ReplaceUsesWith(context_load); | |
| 1200 } else { | |
| 1201 ASSERT(param->kind() == SpecialParameterInstr::kTypeArgs); | |
| 1202 Definition* type_args; | |
| 1203 if (first_param_index > 0) { | |
| 1204 type_args = (*arguments)[0]->definition(); | |
| 1205 } else { | |
| 1206 type_args = callee_graph->constant_null(); | |
| 1207 } | |
| 1208 param->ReplaceUsesWith(type_args); | |
| 1209 } | |
| 1172 } | 1210 } |
| 1173 } | 1211 } |
| 1174 | 1212 |
| 1175 // Check that inlining maintains use lists. | 1213 // Check that inlining maintains use lists. |
| 1176 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists()); | 1214 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->VerifyUseLists()); |
| 1177 } | 1215 } |
| 1178 | 1216 |
| 1179 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { | 1217 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { |
| 1180 intptr_t count = 0; | 1218 intptr_t count = 0; |
| 1181 for (intptr_t i = 0; i < arguments.length(); i++) { | 1219 for (intptr_t i = 0; i < arguments.length(); i++) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1221 } | 1259 } |
| 1222 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), | 1260 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), |
| 1223 &call->function(), call); | 1261 &call->function(), call); |
| 1224 continue; | 1262 continue; |
| 1225 } | 1263 } |
| 1226 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1264 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1227 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1265 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1228 arguments.Add(call->PushArgumentAt(i)->value()); | 1266 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1229 } | 1267 } |
| 1230 InlinedCallData call_data( | 1268 InlinedCallData call_data( |
| 1231 call, &arguments, call_info[call_idx].caller(), | 1269 call, call->FirstParamIndex(), &arguments, |
| 1270 call_info[call_idx].caller(), | |
| 1232 call_info[call_idx].caller_graph->inlining_id()); | 1271 call_info[call_idx].caller_graph->inlining_id()); |
| 1233 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 1272 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 1234 InlineCall(&call_data); | 1273 InlineCall(&call_data); |
| 1235 } | 1274 } |
| 1236 } | 1275 } |
| 1237 } | 1276 } |
| 1238 | 1277 |
| 1239 void InlineClosureCalls() { | 1278 void InlineClosureCalls() { |
| 1240 const GrowableArray<CallSites::ClosureCallInfo>& call_info = | 1279 const GrowableArray<CallSites::ClosureCallInfo>& call_info = |
| 1241 inlining_call_sites_->closure_calls(); | 1280 inlining_call_sites_->closure_calls(); |
| (...skipping 25 matching lines...) Expand all Loading... | |
| 1267 call->ArgumentCount() < target.num_fixed_parameters()) { | 1306 call->ArgumentCount() < target.num_fixed_parameters()) { |
| 1268 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); | 1307 TRACE_INLINING(THR_Print(" Bailout: wrong parameter count\n")); |
| 1269 continue; | 1308 continue; |
| 1270 } | 1309 } |
| 1271 | 1310 |
| 1272 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1311 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1273 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1312 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 1274 arguments.Add(call->PushArgumentAt(i)->value()); | 1313 arguments.Add(call->PushArgumentAt(i)->value()); |
| 1275 } | 1314 } |
| 1276 InlinedCallData call_data( | 1315 InlinedCallData call_data( |
| 1277 call, &arguments, call_info[call_idx].caller(), | 1316 call, call->FirstParamIndex(), &arguments, |
| 1317 call_info[call_idx].caller(), | |
| 1278 call_info[call_idx].caller_graph->inlining_id()); | 1318 call_info[call_idx].caller_graph->inlining_id()); |
| 1279 if (TryInlining(target, call->argument_names(), &call_data)) { | 1319 if (TryInlining(target, call->argument_names(), &call_data)) { |
| 1280 InlineCall(&call_data); | 1320 InlineCall(&call_data); |
| 1281 } | 1321 } |
| 1282 } | 1322 } |
| 1283 } | 1323 } |
| 1284 | 1324 |
| 1285 void InlineInstanceCalls() { | 1325 void InlineInstanceCalls() { |
| 1286 const GrowableArray<CallSites::InstanceCallInfo>& call_info = | 1326 const GrowableArray<CallSites::InstanceCallInfo>& call_info = |
| 1287 inlining_call_sites_->instance_calls(); | 1327 inlining_call_sites_->instance_calls(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1298 } | 1338 } |
| 1299 const Function& cl = call_info[call_idx].caller(); | 1339 const Function& cl = call_info[call_idx].caller(); |
| 1300 intptr_t caller_inlining_id = | 1340 intptr_t caller_inlining_id = |
| 1301 call_info[call_idx].caller_graph->inlining_id(); | 1341 call_info[call_idx].caller_graph->inlining_id(); |
| 1302 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1342 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
| 1303 inliner.Inline(); | 1343 inliner.Inline(); |
| 1304 } | 1344 } |
| 1305 } | 1345 } |
| 1306 | 1346 |
| 1307 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, | 1347 bool AdjustForOptionalParameters(const ParsedFunction& parsed_function, |
| 1348 intptr_t first_param_index, | |
| 1308 const Array& argument_names, | 1349 const Array& argument_names, |
| 1309 GrowableArray<Value*>* arguments, | 1350 GrowableArray<Value*>* arguments, |
| 1310 ZoneGrowableArray<Definition*>* param_stubs, | 1351 ZoneGrowableArray<Definition*>* param_stubs, |
| 1311 FlowGraph* callee_graph) { | 1352 FlowGraph* callee_graph) { |
| 1312 const Function& function = parsed_function.function(); | 1353 const Function& function = parsed_function.function(); |
| 1313 // The language and this code does not support both optional positional | 1354 // The language and this code does not support both optional positional |
| 1314 // and optional named parameters for the same function. | 1355 // and optional named parameters for the same function. |
| 1315 ASSERT(!function.HasOptionalPositionalParameters() || | 1356 ASSERT(!function.HasOptionalPositionalParameters() || |
| 1316 !function.HasOptionalNamedParameters()); | 1357 !function.HasOptionalNamedParameters()); |
| 1317 | 1358 |
| 1318 // TODO(regis): Consider type arguments in arguments. | |
| 1319 intptr_t arg_count = arguments->length(); | 1359 intptr_t arg_count = arguments->length(); |
| 1320 intptr_t param_count = function.NumParameters(); | 1360 intptr_t param_count = function.NumParameters(); |
| 1321 intptr_t fixed_param_count = function.num_fixed_parameters(); | 1361 intptr_t fixed_param_count = function.num_fixed_parameters(); |
| 1322 ASSERT(fixed_param_count <= arg_count); | 1362 ASSERT(fixed_param_count <= arg_count - first_param_index); |
| 1323 ASSERT(arg_count <= param_count); | 1363 ASSERT(arg_count - first_param_index <= param_count); |
| 1324 | 1364 |
| 1325 if (function.HasOptionalPositionalParameters()) { | 1365 if (function.HasOptionalPositionalParameters()) { |
| 1326 // Create a stub for each optional positional parameters with an actual. | 1366 // Create a stub for each optional positional parameters with an actual. |
| 1327 for (intptr_t i = fixed_param_count; i < arg_count; ++i) { | 1367 for (intptr_t i = first_param_index + fixed_param_count; i < arg_count; |
| 1368 ++i) { | |
| 1328 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 1369 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 1329 } | 1370 } |
| 1330 ASSERT(function.NumOptionalPositionalParameters() == | 1371 ASSERT(function.NumOptionalPositionalParameters() == |
| 1331 (param_count - fixed_param_count)); | 1372 (param_count - fixed_param_count)); |
| 1332 // For each optional positional parameter without an actual, add its | 1373 // For each optional positional parameter without an actual, add its |
| 1333 // default value. | 1374 // default value. |
| 1334 for (intptr_t i = arg_count; i < param_count; ++i) { | 1375 for (intptr_t i = arg_count - first_param_index; i < param_count; ++i) { |
| 1335 const Instance& object = | 1376 const Instance& object = |
| 1336 parsed_function.DefaultParameterValueAt(i - fixed_param_count); | 1377 parsed_function.DefaultParameterValueAt(i - fixed_param_count); |
| 1337 ConstantInstr* constant = new (Z) ConstantInstr(object); | 1378 ConstantInstr* constant = new (Z) ConstantInstr(object); |
| 1338 arguments->Add(NULL); | 1379 arguments->Add(NULL); |
| 1339 param_stubs->Add(constant); | 1380 param_stubs->Add(constant); |
| 1340 } | 1381 } |
| 1341 return true; | 1382 return true; |
| 1342 } | 1383 } |
| 1343 | 1384 |
| 1344 ASSERT(function.HasOptionalNamedParameters()); | 1385 ASSERT(function.HasOptionalNamedParameters()); |
| 1345 | 1386 |
| 1346 // Passed arguments must match fixed parameters plus named arguments. | 1387 // Passed arguments (not counting optional type args) must match fixed |
| 1388 // parameters plus named arguments. | |
| 1347 intptr_t argument_names_count = | 1389 intptr_t argument_names_count = |
| 1348 (argument_names.IsNull()) ? 0 : argument_names.Length(); | 1390 (argument_names.IsNull()) ? 0 : argument_names.Length(); |
| 1349 ASSERT(arg_count == (fixed_param_count + argument_names_count)); | 1391 ASSERT((arg_count - first_param_index) == |
| 1392 (fixed_param_count + argument_names_count)); | |
| 1350 | 1393 |
| 1351 // Fast path when no optional named parameters are given. | 1394 // Fast path when no optional named parameters are given. |
| 1352 if (argument_names_count == 0) { | 1395 if (argument_names_count == 0) { |
| 1353 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { | 1396 for (intptr_t i = 0; i < param_count - fixed_param_count; ++i) { |
| 1354 arguments->Add(NULL); | 1397 arguments->Add(NULL); |
| 1355 param_stubs->Add(GetDefaultValue(i, parsed_function)); | 1398 param_stubs->Add(GetDefaultValue(i, parsed_function)); |
| 1356 } | 1399 } |
| 1357 return true; | 1400 return true; |
| 1358 } | 1401 } |
| 1359 | 1402 |
| 1360 // Otherwise, build a collection of name/argument pairs. | 1403 // Otherwise, build a collection of name/argument pairs. |
| 1361 GrowableArray<NamedArgument> named_args(argument_names_count); | 1404 GrowableArray<NamedArgument> named_args(argument_names_count); |
| 1362 for (intptr_t i = 0; i < argument_names.Length(); ++i) { | 1405 for (intptr_t i = 0; i < argument_names.Length(); ++i) { |
| 1363 String& arg_name = String::Handle(caller_graph_->zone()); | 1406 String& arg_name = String::Handle(caller_graph_->zone()); |
| 1364 arg_name ^= argument_names.At(i); | 1407 arg_name ^= argument_names.At(i); |
| 1365 named_args.Add( | 1408 named_args.Add(NamedArgument( |
| 1366 NamedArgument(&arg_name, (*arguments)[i + fixed_param_count])); | 1409 &arg_name, (*arguments)[first_param_index + fixed_param_count + i])); |
| 1367 } | 1410 } |
| 1368 | 1411 |
| 1369 // Truncate the arguments array to just fixed parameters. | 1412 // Truncate the arguments array to just type args and fixed parameters. |
| 1370 arguments->TruncateTo(fixed_param_count); | 1413 arguments->TruncateTo(first_param_index + fixed_param_count); |
| 1371 | 1414 |
| 1372 // For each optional named parameter, add the actual argument or its | 1415 // For each optional named parameter, add the actual argument or its |
| 1373 // default if no argument is passed. | 1416 // default if no argument is passed. |
| 1374 intptr_t match_count = 0; | 1417 intptr_t match_count = 0; |
| 1375 for (intptr_t i = fixed_param_count; i < param_count; ++i) { | 1418 for (intptr_t i = fixed_param_count; i < param_count; ++i) { |
| 1376 String& param_name = String::Handle(function.ParameterNameAt(i)); | 1419 String& param_name = String::Handle(function.ParameterNameAt(i)); |
| 1377 // Search for and add the named argument. | 1420 // Search for and add the named argument. |
| 1378 Value* arg = NULL; | 1421 Value* arg = NULL; |
| 1379 for (intptr_t j = 0; j < named_args.length(); ++j) { | 1422 for (intptr_t j = 0; j < named_args.length(); ++j) { |
| 1380 if (param_name.Equals(*named_args[j].name)) { | 1423 if (param_name.Equals(*named_args[j].name)) { |
| 1381 arg = named_args[j].value; | 1424 arg = named_args[j].value; |
| 1382 match_count++; | 1425 match_count++; |
| 1383 break; | 1426 break; |
| 1384 } | 1427 } |
| 1385 } | 1428 } |
| 1386 arguments->Add(arg); | 1429 arguments->Add(arg); |
| 1387 // Create a stub for the argument or use the parameter's default value. | 1430 // Create a stub for the argument or use the parameter's default value. |
| 1388 if (arg != NULL) { | 1431 if (arg != NULL) { |
| 1389 param_stubs->Add(CreateParameterStub(i, arg, callee_graph)); | 1432 param_stubs->Add( |
| 1433 CreateParameterStub(first_param_index + i, arg, callee_graph)); | |
| 1390 } else { | 1434 } else { |
| 1391 param_stubs->Add( | 1435 param_stubs->Add( |
| 1392 GetDefaultValue(i - fixed_param_count, parsed_function)); | 1436 GetDefaultValue(i - fixed_param_count, parsed_function)); |
| 1393 } | 1437 } |
| 1394 } | 1438 } |
| 1395 return argument_names_count == match_count; | 1439 return argument_names_count == match_count; |
| 1396 } | 1440 } |
| 1397 | 1441 |
| 1398 FlowGraphInliner* inliner_; | 1442 FlowGraphInliner* inliner_; |
| 1399 FlowGraph* caller_graph_; | 1443 FlowGraph* caller_graph_; |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1522 target_info.IsSingleCid() && | 1566 target_info.IsSingleCid() && |
| 1523 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { | 1567 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
| 1524 owner_->inlined_ = true; | 1568 owner_->inlined_ = true; |
| 1525 return true; | 1569 return true; |
| 1526 } | 1570 } |
| 1527 | 1571 |
| 1528 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1572 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
| 1529 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1573 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
| 1530 arguments.Add(call_->PushArgumentAt(i)->value()); | 1574 arguments.Add(call_->PushArgumentAt(i)->value()); |
| 1531 } | 1575 } |
| 1532 InlinedCallData call_data(call_, &arguments, caller_function_, | 1576 InlinedCallData call_data(call_, call_->instance_call()->FirstParamIndex(), |
| 1533 caller_inlining_id_); | 1577 &arguments, caller_function_, caller_inlining_id_); |
| 1534 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); | 1578 Function& target = Function::ZoneHandle(zone(), target_info.target->raw()); |
| 1535 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), | 1579 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
| 1536 &call_data)) { | 1580 &call_data)) { |
| 1537 return false; | 1581 return false; |
| 1538 } | 1582 } |
| 1539 | 1583 |
| 1540 FlowGraph* callee_graph = call_data.callee_graph; | 1584 FlowGraph* callee_graph = call_data.callee_graph; |
| 1541 call_data.exit_collector->PrepareGraphs(callee_graph); | 1585 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1542 inlined_entries_.Add(callee_graph->graph_entry()); | 1586 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1543 exit_collector_->Union(call_data.exit_collector); | 1587 exit_collector_->Union(call_data.exit_collector); |
| 1544 | 1588 |
| 1545 // Replace parameter stubs and constants. Replace the receiver argument | 1589 // Replace parameter stubs and constants. Replace the receiver argument |
|
Vyacheslav Egorov (Google)
2017/06/28 14:56:02
I think that parameter stubs replacement that happ
regis
2017/06/28 21:03:59
That was it! Thanks!
I moved this code into a shar
| |
| 1546 // with a redefinition to prevent code from the inlined body from being | 1590 // with a redefinition to prevent code from the inlined body from being |
| 1547 // hoisted above the inlined entry. | 1591 // hoisted above the inlined entry. |
| 1548 ASSERT(arguments.length() > 0); | 1592 ASSERT(arguments.length() > 0); |
| 1549 Value* actual = arguments[0]; | 1593 Value* actual = arguments[0]; |
| 1550 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); | 1594 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); |
| 1551 redefinition->set_ssa_temp_index( | 1595 redefinition->set_ssa_temp_index( |
| 1552 owner_->caller_graph()->alloc_ssa_temp_index()); | 1596 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1553 if (target_info.IsSingleCid()) { | 1597 if (target_info.IsSingleCid()) { |
| 1554 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); | 1598 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); |
| 1555 } | 1599 } |
| 1556 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | 1600 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); |
| 1557 Definition* stub = (*call_data.parameter_stubs)[0]; | 1601 Definition* stub = (*call_data.parameter_stubs)[0]; |
| 1558 stub->ReplaceUsesWith(redefinition); | 1602 stub->ReplaceUsesWith(redefinition); |
| 1559 | 1603 |
| 1560 for (intptr_t i = 1; i < arguments.length(); ++i) { | 1604 for (intptr_t i = 1; i < arguments.length(); ++i) { |
| 1561 actual = arguments[i]; | 1605 actual = arguments[i]; |
| 1562 if (actual != NULL) { | 1606 if (actual != NULL) { |
| 1563 stub = (*call_data.parameter_stubs)[i]; | 1607 stub = (*call_data.parameter_stubs)[i]; |
| 1564 stub->ReplaceUsesWith(actual->definition()); | 1608 stub->ReplaceUsesWith(actual->definition()); |
| 1565 } | 1609 } |
| 1566 } | 1610 } |
| 1567 GrowableArray<Definition*>* defns = | 1611 GrowableArray<Definition*>* defns = |
| 1568 callee_graph->graph_entry()->initial_definitions(); | 1612 callee_graph->graph_entry()->initial_definitions(); |
| 1569 for (intptr_t i = 0; i < defns->length(); ++i) { | 1613 for (intptr_t i = 0; i < defns->length(); ++i) { |
| 1570 ConstantInstr* constant = (*defns)[i]->AsConstant(); | 1614 ConstantInstr* constant = (*defns)[i]->AsConstant(); |
| 1571 if ((constant != NULL) && constant->HasUses()) { | 1615 if ((constant != NULL) && constant->HasUses()) { |
| 1572 constant->ReplaceUsesWith( | 1616 constant->ReplaceUsesWith( |
| 1573 owner_->caller_graph()->GetConstant(constant->value())); | 1617 owner_->caller_graph()->GetConstant(constant->value())); |
| 1574 } | 1618 } |
| 1575 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | 1619 SpecialParameterInstr* param = (*defns)[i]->AsSpecialParameter(); |
| 1576 if ((context != NULL) && context->HasUses()) { | 1620 if ((param != NULL) && param->HasUses()) { |
| 1577 ASSERT(call_data.call->IsClosureCall()); | 1621 if (param->kind() == SpecialParameterInstr::kContext) { |
| 1578 LoadFieldInstr* context_load = new (Z) | 1622 ASSERT(call_data.call->IsClosureCall()); |
| 1579 LoadFieldInstr(new Value(redefinition), Closure::context_offset(), | 1623 LoadFieldInstr* context_load = new (Z) LoadFieldInstr( |
| 1580 AbstractType::ZoneHandle(zone(), AbstractType::null()), | 1624 new Value(redefinition), Closure::context_offset(), |
| 1581 call_data.call->token_pos()); | 1625 AbstractType::ZoneHandle(zone(), AbstractType::null()), |
| 1582 context_load->set_is_immutable(true); | 1626 call_data.call->token_pos()); |
| 1583 context_load->set_ssa_temp_index( | 1627 context_load->set_is_immutable(true); |
| 1584 owner_->caller_graph()->alloc_ssa_temp_index()); | 1628 context_load->set_ssa_temp_index( |
| 1585 context_load->InsertAfter(redefinition); | 1629 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1586 context->ReplaceUsesWith(context_load); | 1630 context_load->InsertAfter(redefinition); |
| 1631 param->ReplaceUsesWith(context_load); | |
| 1632 } else { | |
| 1633 ASSERT(param->kind() == SpecialParameterInstr::kTypeArgs); | |
| 1634 UNIMPLEMENTED(); // TODO(regis): Why am I not hitting this? No uses? | |
| 1635 } | |
| 1587 } | 1636 } |
| 1588 } | 1637 } |
| 1589 return true; | 1638 return true; |
| 1590 } | 1639 } |
| 1591 | 1640 |
| 1592 | 1641 |
| 1593 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { | 1642 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { |
| 1594 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1643 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
| 1595 Value* input = second->InputAt(i); | 1644 Value* input = second->InputAt(i); |
| 1596 input->definition()->AddInputUse(input); | 1645 input->definition()->AddInputUse(input); |
| (...skipping 2170 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3767 } | 3816 } |
| 3768 | 3817 |
| 3769 default: | 3818 default: |
| 3770 return false; | 3819 return false; |
| 3771 } | 3820 } |
| 3772 } | 3821 } |
| 3773 | 3822 |
| 3774 | 3823 |
| 3775 } // namespace dart | 3824 } // namespace dart |
| 3776 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3825 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| OLD | NEW |