| 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 | 4 |
| 5 #include "vm/flow_graph_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
| 6 | 6 |
| 7 #include "vm/block_scheduler.h" | 7 #include "vm/block_scheduler.h" |
| 8 #include "vm/compiler.h" | 8 #include "vm/compiler.h" |
| 9 #include "vm/flags.h" | 9 #include "vm/flags.h" |
| 10 #include "vm/flow_graph.h" | 10 #include "vm/flow_graph.h" |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 DEFINE_FLAG(bool, enable_inlining_annotations, false, | 57 DEFINE_FLAG(bool, enable_inlining_annotations, false, |
| 58 "Enable inlining annotations"); | 58 "Enable inlining annotations"); |
| 59 | 59 |
| 60 DECLARE_FLAG(bool, compiler_stats); | 60 DECLARE_FLAG(bool, compiler_stats); |
| 61 DECLARE_FLAG(bool, enable_type_checks); | 61 DECLARE_FLAG(bool, enable_type_checks); |
| 62 DECLARE_FLAG(int, deoptimization_counter_threshold); | 62 DECLARE_FLAG(int, deoptimization_counter_threshold); |
| 63 DECLARE_FLAG(bool, print_flow_graph); | 63 DECLARE_FLAG(bool, print_flow_graph); |
| 64 DECLARE_FLAG(bool, print_flow_graph_optimized); | 64 DECLARE_FLAG(bool, print_flow_graph_optimized); |
| 65 DECLARE_FLAG(bool, verify_compiler); | 65 DECLARE_FLAG(bool, verify_compiler); |
| 66 | 66 |
| 67 // Quick access to the current zone. |
| 68 #define Z (zone()) |
| 69 |
| 67 #define TRACE_INLINING(statement) \ | 70 #define TRACE_INLINING(statement) \ |
| 68 do { \ | 71 do { \ |
| 69 if (FLAG_trace_inlining) statement; \ | 72 if (FLAG_trace_inlining) statement; \ |
| 70 } while (false) | 73 } while (false) |
| 71 | 74 |
| 72 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ | 75 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ |
| 73 do { \ | 76 do { \ |
| 74 if (FLAG_print_inlining_tree) { \ | 77 if (FLAG_print_inlining_tree) { \ |
| 75 inlined_info_.Add(InlinedInfo( \ | 78 inlined_info_.Add(InlinedInfo( \ |
| 76 caller, target, inlining_depth_, instance_call, comment)); \ | 79 caller, target, inlining_depth_, instance_call, comment)); \ |
| (...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 431 private: | 434 private: |
| 432 bool CheckInlinedDuplicate(const Function& target); | 435 bool CheckInlinedDuplicate(const Function& target); |
| 433 bool CheckNonInlinedDuplicate(const Function& target); | 436 bool CheckNonInlinedDuplicate(const Function& target); |
| 434 | 437 |
| 435 bool TryInliningPoly(intptr_t receiver_cid, const Function& target); | 438 bool TryInliningPoly(intptr_t receiver_cid, const Function& target); |
| 436 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); | 439 bool TryInlineRecognizedMethod(intptr_t receiver_cid, const Function& target); |
| 437 | 440 |
| 438 TargetEntryInstr* BuildDecisionGraph(); | 441 TargetEntryInstr* BuildDecisionGraph(); |
| 439 | 442 |
| 440 Isolate* isolate() const; | 443 Isolate* isolate() const; |
| 444 Zone* zone() const; |
| 441 | 445 |
| 442 CallSiteInliner* const owner_; | 446 CallSiteInliner* const owner_; |
| 443 PolymorphicInstanceCallInstr* const call_; | 447 PolymorphicInstanceCallInstr* const call_; |
| 444 const intptr_t num_variants_; | 448 const intptr_t num_variants_; |
| 445 GrowableArray<CidTarget> variants_; | 449 GrowableArray<CidTarget> variants_; |
| 446 | 450 |
| 447 GrowableArray<CidTarget> inlined_variants_; | 451 GrowableArray<CidTarget> inlined_variants_; |
| 448 GrowableArray<CidTarget> non_inlined_variants_; | 452 GrowableArray<CidTarget> non_inlined_variants_; |
| 449 GrowableArray<BlockEntryInstr*> inlined_entries_; | 453 GrowableArray<BlockEntryInstr*> inlined_entries_; |
| 450 InlineExitCollector* exit_collector_; | 454 InlineExitCollector* exit_collector_; |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 483 inlined_recursive_call_(false), | 487 inlined_recursive_call_(false), |
| 484 inlining_depth_(1), | 488 inlining_depth_(1), |
| 485 inlining_recursion_depth_(0), | 489 inlining_recursion_depth_(0), |
| 486 collected_call_sites_(NULL), | 490 collected_call_sites_(NULL), |
| 487 inlining_call_sites_(NULL), | 491 inlining_call_sites_(NULL), |
| 488 function_cache_(), | 492 function_cache_(), |
| 489 inlined_info_() { } | 493 inlined_info_() { } |
| 490 | 494 |
| 491 FlowGraph* caller_graph() const { return caller_graph_; } | 495 FlowGraph* caller_graph() const { return caller_graph_; } |
| 492 | 496 |
| 497 Thread* thread() const { return caller_graph_->thread(); } |
| 493 Isolate* isolate() const { return caller_graph_->isolate(); } | 498 Isolate* isolate() const { return caller_graph_->isolate(); } |
| 499 Zone* zone() const { return caller_graph_->zone(); } |
| 494 | 500 |
| 495 // Inlining heuristics based on Cooper et al. 2008. | 501 // Inlining heuristics based on Cooper et al. 2008. |
| 496 bool ShouldWeInline(const Function& callee, | 502 bool ShouldWeInline(const Function& callee, |
| 497 intptr_t instr_count, | 503 intptr_t instr_count, |
| 498 intptr_t call_site_count, | 504 intptr_t call_site_count, |
| 499 intptr_t const_arg_count) { | 505 intptr_t const_arg_count) { |
| 500 if (FlowGraphInliner::AlwaysInline(callee)) { | 506 if (FlowGraphInliner::AlwaysInline(callee)) { |
| 501 return true; | 507 return true; |
| 502 } | 508 } |
| 503 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 509 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 578 return static_cast<double>(inlined_size_) / | 584 return static_cast<double>(inlined_size_) / |
| 579 static_cast<double>(initial_size_); | 585 static_cast<double>(initial_size_); |
| 580 } | 586 } |
| 581 | 587 |
| 582 // Helper to create a parameter stub from an actual argument. | 588 // Helper to create a parameter stub from an actual argument. |
| 583 Definition* CreateParameterStub(intptr_t i, | 589 Definition* CreateParameterStub(intptr_t i, |
| 584 Value* argument, | 590 Value* argument, |
| 585 FlowGraph* graph) { | 591 FlowGraph* graph) { |
| 586 ConstantInstr* constant = argument->definition()->AsConstant(); | 592 ConstantInstr* constant = argument->definition()->AsConstant(); |
| 587 if (constant != NULL) { | 593 if (constant != NULL) { |
| 588 return new(isolate()) ConstantInstr(constant->value()); | 594 return new(Z) ConstantInstr(constant->value()); |
| 589 } else { | 595 } else { |
| 590 return new(isolate()) ParameterInstr(i, graph->graph_entry()); | 596 return new(Z) ParameterInstr(i, graph->graph_entry()); |
| 591 } | 597 } |
| 592 } | 598 } |
| 593 | 599 |
| 594 bool TryInlining(const Function& function, | 600 bool TryInlining(const Function& function, |
| 595 const Array& argument_names, | 601 const Array& argument_names, |
| 596 InlinedCallData* call_data) { | 602 InlinedCallData* call_data) { |
| 597 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 603 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", |
| 598 function.ToCString(), | 604 function.ToCString(), |
| 599 function.deoptimization_counter())); | 605 function.deoptimization_counter())); |
| 600 | 606 |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 667 ParsedFunction* parsed_function; | 673 ParsedFunction* parsed_function; |
| 668 { | 674 { |
| 669 TimerScope timer(FLAG_compiler_stats, | 675 TimerScope timer(FLAG_compiler_stats, |
| 670 &CompilerStats::graphinliner_parse_timer, | 676 &CompilerStats::graphinliner_parse_timer, |
| 671 isolate()); | 677 isolate()); |
| 672 parsed_function = GetParsedFunction(function, &in_cache); | 678 parsed_function = GetParsedFunction(function, &in_cache); |
| 673 } | 679 } |
| 674 | 680 |
| 675 // Load IC data for the callee. | 681 // Load IC data for the callee. |
| 676 ZoneGrowableArray<const ICData*>* ic_data_array = | 682 ZoneGrowableArray<const ICData*>* ic_data_array = |
| 677 new(isolate()) ZoneGrowableArray<const ICData*>(); | 683 new(Z) ZoneGrowableArray<const ICData*>(); |
| 678 function.RestoreICDataMap(ic_data_array); | 684 function.RestoreICDataMap(ic_data_array); |
| 679 | 685 |
| 680 // Build the callee graph. | 686 // Build the callee graph. |
| 681 InlineExitCollector* exit_collector = | 687 InlineExitCollector* exit_collector = |
| 682 new(isolate()) InlineExitCollector(caller_graph_, call); | 688 new(Z) InlineExitCollector(caller_graph_, call); |
| 683 FlowGraphBuilder builder(parsed_function, | 689 FlowGraphBuilder builder(parsed_function, |
| 684 *ic_data_array, | 690 *ic_data_array, |
| 685 exit_collector, | 691 exit_collector, |
| 686 Isolate::kNoDeoptId); | 692 Isolate::kNoDeoptId); |
| 687 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 693 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 688 FlowGraph* callee_graph; | 694 FlowGraph* callee_graph; |
| 689 { | 695 { |
| 690 TimerScope timer(FLAG_compiler_stats, | 696 TimerScope timer(FLAG_compiler_stats, |
| 691 &CompilerStats::graphinliner_build_timer, | 697 &CompilerStats::graphinliner_build_timer, |
| 692 isolate()); | 698 isolate()); |
| 693 callee_graph = builder.BuildGraph(); | 699 callee_graph = builder.BuildGraph(); |
| 694 } | 700 } |
| 695 | 701 |
| 696 // The parameter stubs are a copy of the actual arguments providing | 702 // The parameter stubs are a copy of the actual arguments providing |
| 697 // concrete information about the values, for example constant values, | 703 // concrete information about the values, for example constant values, |
| 698 // without linking between the caller and callee graphs. | 704 // without linking between the caller and callee graphs. |
| 699 // TODO(zerny): Put more information in the stubs, eg, type information. | 705 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 700 ZoneGrowableArray<Definition*>* param_stubs = | 706 ZoneGrowableArray<Definition*>* param_stubs = |
| 701 new(isolate()) ZoneGrowableArray<Definition*>( | 707 new(Z) ZoneGrowableArray<Definition*>( |
| 702 function.NumParameters()); | 708 function.NumParameters()); |
| 703 | 709 |
| 704 // Create a parameter stub for each fixed positional parameter. | 710 // Create a parameter stub for each fixed positional parameter. |
| 705 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 711 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| 706 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); | 712 param_stubs->Add(CreateParameterStub(i, (*arguments)[i], callee_graph)); |
| 707 } | 713 } |
| 708 | 714 |
| 709 // If the callee has optional parameters, rebuild the argument and stub | 715 // If the callee has optional parameters, rebuild the argument and stub |
| 710 // arrays so that actual arguments are in one-to-one with the formal | 716 // arrays so that actual arguments are in one-to-one with the formal |
| 711 // parameters. | 717 // parameters. |
| (...skipping 254 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 966 callee_graph->graph_entry()->initial_definitions(); | 972 callee_graph->graph_entry()->initial_definitions(); |
| 967 for (intptr_t i = 0; i < defns->length(); ++i) { | 973 for (intptr_t i = 0; i < defns->length(); ++i) { |
| 968 ConstantInstr* constant = (*defns)[i]->AsConstant(); | 974 ConstantInstr* constant = (*defns)[i]->AsConstant(); |
| 969 if ((constant != NULL) && constant->HasUses()) { | 975 if ((constant != NULL) && constant->HasUses()) { |
| 970 constant->ReplaceUsesWith( | 976 constant->ReplaceUsesWith( |
| 971 caller_graph_->GetConstant(constant->value())); | 977 caller_graph_->GetConstant(constant->value())); |
| 972 } | 978 } |
| 973 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | 979 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); |
| 974 if ((context != NULL) && context->HasUses()) { | 980 if ((context != NULL) && context->HasUses()) { |
| 975 ASSERT(call->IsClosureCall()); | 981 ASSERT(call->IsClosureCall()); |
| 976 LoadFieldInstr* context_load = new(isolate()) LoadFieldInstr( | 982 LoadFieldInstr* context_load = new(Z) LoadFieldInstr( |
| 977 new Value((*arguments)[0]->definition()), | 983 new Value((*arguments)[0]->definition()), |
| 978 Closure::context_offset(), | 984 Closure::context_offset(), |
| 979 AbstractType::ZoneHandle(isolate(), AbstractType::null()), | 985 AbstractType::ZoneHandle(isolate(), AbstractType::null()), |
| 980 call_data->call->token_pos()); | 986 call_data->call->token_pos()); |
| 981 context_load->set_is_immutable(true); | 987 context_load->set_is_immutable(true); |
| 982 context_load->set_ssa_temp_index( | 988 context_load->set_ssa_temp_index( |
| 983 caller_graph_->alloc_ssa_temp_index()); | 989 caller_graph_->alloc_ssa_temp_index()); |
| 984 context_load->InsertBefore(callee_entry->next()); | 990 context_load->InsertBefore(callee_entry->next()); |
| 985 context->ReplaceUsesWith(context_load); | 991 context->ReplaceUsesWith(context_load); |
| 986 } | 992 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1003 // TODO(zerny): Use a hash map for the cache. | 1009 // TODO(zerny): Use a hash map for the cache. |
| 1004 for (intptr_t i = 0; i < function_cache_.length(); ++i) { | 1010 for (intptr_t i = 0; i < function_cache_.length(); ++i) { |
| 1005 ParsedFunction* parsed_function = function_cache_[i]; | 1011 ParsedFunction* parsed_function = function_cache_[i]; |
| 1006 if (parsed_function->function().raw() == function.raw()) { | 1012 if (parsed_function->function().raw() == function.raw()) { |
| 1007 *in_cache = true; | 1013 *in_cache = true; |
| 1008 return parsed_function; | 1014 return parsed_function; |
| 1009 } | 1015 } |
| 1010 } | 1016 } |
| 1011 *in_cache = false; | 1017 *in_cache = false; |
| 1012 ParsedFunction* parsed_function = | 1018 ParsedFunction* parsed_function = |
| 1013 new(isolate()) ParsedFunction(isolate(), function); | 1019 new(Z) ParsedFunction(thread(), function); |
| 1014 Parser::ParseFunction(parsed_function); | 1020 Parser::ParseFunction(parsed_function); |
| 1015 parsed_function->AllocateVariables(); | 1021 parsed_function->AllocateVariables(); |
| 1016 return parsed_function; | 1022 return parsed_function; |
| 1017 } | 1023 } |
| 1018 | 1024 |
| 1019 // Include special handling for List. factory: inlining it is not helpful | 1025 // Include special handling for List. factory: inlining it is not helpful |
| 1020 // if the incoming argument is a non-constant value. | 1026 // if the incoming argument is a non-constant value. |
| 1021 // TODO(srdjan): Fix inlining of List. factory. | 1027 // TODO(srdjan): Fix inlining of List. factory. |
| 1022 void InlineStaticCalls() { | 1028 void InlineStaticCalls() { |
| 1023 const GrowableArray<CallSites::StaticCallInfo>& call_info = | 1029 const GrowableArray<CallSites::StaticCallInfo>& call_info = |
| (...skipping 141 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1165 } | 1171 } |
| 1166 ASSERT(function.NumOptionalPositionalParameters() == | 1172 ASSERT(function.NumOptionalPositionalParameters() == |
| 1167 (param_count - fixed_param_count)); | 1173 (param_count - fixed_param_count)); |
| 1168 // For each optional positional parameter without an actual, add its | 1174 // For each optional positional parameter without an actual, add its |
| 1169 // default value. | 1175 // default value. |
| 1170 for (intptr_t i = arg_count; i < param_count; ++i) { | 1176 for (intptr_t i = arg_count; i < param_count; ++i) { |
| 1171 const Object& object = | 1177 const Object& object = |
| 1172 Object::ZoneHandle( | 1178 Object::ZoneHandle( |
| 1173 parsed_function.default_parameter_values().At( | 1179 parsed_function.default_parameter_values().At( |
| 1174 i - fixed_param_count)); | 1180 i - fixed_param_count)); |
| 1175 ConstantInstr* constant = new(isolate()) ConstantInstr(object); | 1181 ConstantInstr* constant = new(Z) ConstantInstr(object); |
| 1176 arguments->Add(NULL); | 1182 arguments->Add(NULL); |
| 1177 param_stubs->Add(constant); | 1183 param_stubs->Add(constant); |
| 1178 } | 1184 } |
| 1179 return true; | 1185 return true; |
| 1180 } | 1186 } |
| 1181 | 1187 |
| 1182 ASSERT(function.HasOptionalNamedParameters()); | 1188 ASSERT(function.HasOptionalNamedParameters()); |
| 1183 | 1189 |
| 1184 // Passed arguments must match fixed parameters plus named arguments. | 1190 // Passed arguments must match fixed parameters plus named arguments. |
| 1185 intptr_t argument_names_count = | 1191 intptr_t argument_names_count = |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1253 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1259 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
| 1254 PolymorphicInstanceCallInstr* call, | 1260 PolymorphicInstanceCallInstr* call, |
| 1255 const Function& caller_function) | 1261 const Function& caller_function) |
| 1256 : owner_(owner), | 1262 : owner_(owner), |
| 1257 call_(call), | 1263 call_(call), |
| 1258 num_variants_(call->ic_data().NumberOfChecks()), | 1264 num_variants_(call->ic_data().NumberOfChecks()), |
| 1259 variants_(num_variants_), | 1265 variants_(num_variants_), |
| 1260 inlined_variants_(num_variants_), | 1266 inlined_variants_(num_variants_), |
| 1261 non_inlined_variants_(num_variants_), | 1267 non_inlined_variants_(num_variants_), |
| 1262 inlined_entries_(num_variants_), | 1268 inlined_entries_(num_variants_), |
| 1263 exit_collector_(new(isolate()) | 1269 exit_collector_(new(Z) |
| 1264 InlineExitCollector(owner->caller_graph(), call)), | 1270 InlineExitCollector(owner->caller_graph(), call)), |
| 1265 caller_function_(caller_function) { | 1271 caller_function_(caller_function) { |
| 1266 } | 1272 } |
| 1267 | 1273 |
| 1268 | 1274 |
| 1269 Isolate* PolymorphicInliner::isolate() const { | 1275 Isolate* PolymorphicInliner::isolate() const { |
| 1270 return owner_->caller_graph()->isolate(); | 1276 return owner_->caller_graph()->isolate(); |
| 1271 } | 1277 } |
| 1272 | 1278 |
| 1273 | 1279 |
| 1280 Zone* PolymorphicInliner::zone() const { |
| 1281 return owner_->caller_graph()->zone(); |
| 1282 } |
| 1283 |
| 1284 |
| 1274 // Inlined bodies are shared if two different class ids have the same | 1285 // Inlined bodies are shared if two different class ids have the same |
| 1275 // inlined target. This sharing is represented by using three different | 1286 // inlined target. This sharing is represented by using three different |
| 1276 // types of entries in the inlined_entries_ array: | 1287 // types of entries in the inlined_entries_ array: |
| 1277 // | 1288 // |
| 1278 // * GraphEntry: the inlined body is not shared. | 1289 // * GraphEntry: the inlined body is not shared. |
| 1279 // | 1290 // |
| 1280 // * TargetEntry: the inlined body is shared and this is the first variant. | 1291 // * TargetEntry: the inlined body is shared and this is the first variant. |
| 1281 // | 1292 // |
| 1282 // * JoinEntry: the inlined body is shared and this is a subsequent variant. | 1293 // * JoinEntry: the inlined body is shared and this is a subsequent variant. |
| 1283 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { | 1294 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1303 old_target->ReplaceAsPredecessorWith(new_join); | 1314 old_target->ReplaceAsPredecessorWith(new_join); |
| 1304 for (intptr_t j = 0; j < old_target->dominated_blocks().length(); ++j) { | 1315 for (intptr_t j = 0; j < old_target->dominated_blocks().length(); ++j) { |
| 1305 BlockEntryInstr* block = old_target->dominated_blocks()[j]; | 1316 BlockEntryInstr* block = old_target->dominated_blocks()[j]; |
| 1306 new_join->AddDominatedBlock(block); | 1317 new_join->AddDominatedBlock(block); |
| 1307 } | 1318 } |
| 1308 // Create a new target with the join as unconditional successor. | 1319 // Create a new target with the join as unconditional successor. |
| 1309 TargetEntryInstr* new_target = | 1320 TargetEntryInstr* new_target = |
| 1310 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), | 1321 new TargetEntryInstr(owner_->caller_graph()->allocate_block_id(), |
| 1311 old_target->try_index()); | 1322 old_target->try_index()); |
| 1312 new_target->InheritDeoptTarget(isolate(), new_join); | 1323 new_target->InheritDeoptTarget(isolate(), new_join); |
| 1313 GotoInstr* new_goto = new(isolate()) GotoInstr(new_join); | 1324 GotoInstr* new_goto = new(Z) GotoInstr(new_join); |
| 1314 new_goto->InheritDeoptTarget(isolate(), new_join); | 1325 new_goto->InheritDeoptTarget(isolate(), new_join); |
| 1315 new_target->LinkTo(new_goto); | 1326 new_target->LinkTo(new_goto); |
| 1316 new_target->set_last_instruction(new_goto); | 1327 new_target->set_last_instruction(new_goto); |
| 1317 new_join->predecessors_.Add(new_target); | 1328 new_join->predecessors_.Add(new_target); |
| 1318 | 1329 |
| 1319 // Record the new target for the first variant. | 1330 // Record the new target for the first variant. |
| 1320 inlined_entries_[i] = new_target; | 1331 inlined_entries_[i] = new_target; |
| 1321 } | 1332 } |
| 1322 ASSERT(inlined_entries_[i]->IsTargetEntry()); | 1333 ASSERT(inlined_entries_[i]->IsTargetEntry()); |
| 1323 // Record the shared join for this variant. | 1334 // Record the shared join for this variant. |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1365 FlowGraph* callee_graph = call_data.callee_graph; | 1376 FlowGraph* callee_graph = call_data.callee_graph; |
| 1366 call_data.exit_collector->PrepareGraphs(callee_graph); | 1377 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1367 inlined_entries_.Add(callee_graph->graph_entry()); | 1378 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1368 exit_collector_->Union(call_data.exit_collector); | 1379 exit_collector_->Union(call_data.exit_collector); |
| 1369 | 1380 |
| 1370 // Replace parameter stubs and constants. Replace the receiver argument | 1381 // Replace parameter stubs and constants. Replace the receiver argument |
| 1371 // with a redefinition to prevent code from the inlined body from being | 1382 // with a redefinition to prevent code from the inlined body from being |
| 1372 // hoisted above the inlined entry. | 1383 // hoisted above the inlined entry. |
| 1373 ASSERT(arguments.length() > 0); | 1384 ASSERT(arguments.length() > 0); |
| 1374 Value* actual = arguments[0]; | 1385 Value* actual = arguments[0]; |
| 1375 RedefinitionInstr* redefinition = new(isolate()) | 1386 RedefinitionInstr* redefinition = new(Z) |
| 1376 RedefinitionInstr(actual->Copy(isolate())); | 1387 RedefinitionInstr(actual->Copy(isolate())); |
| 1377 redefinition->set_ssa_temp_index( | 1388 redefinition->set_ssa_temp_index( |
| 1378 owner_->caller_graph()->alloc_ssa_temp_index()); | 1389 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1379 redefinition->UpdateType(CompileType::FromCid(receiver_cid)); | 1390 redefinition->UpdateType(CompileType::FromCid(receiver_cid)); |
| 1380 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | 1391 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); |
| 1381 Definition* stub = (*call_data.parameter_stubs)[0]; | 1392 Definition* stub = (*call_data.parameter_stubs)[0]; |
| 1382 stub->ReplaceUsesWith(redefinition); | 1393 stub->ReplaceUsesWith(redefinition); |
| 1383 | 1394 |
| 1384 for (intptr_t i = 1; i < arguments.length(); ++i) { | 1395 for (intptr_t i = 1; i < arguments.length(); ++i) { |
| 1385 actual = arguments[i]; | 1396 actual = arguments[i]; |
| 1386 if (actual != NULL) { | 1397 if (actual != NULL) { |
| 1387 stub = (*call_data.parameter_stubs)[i]; | 1398 stub = (*call_data.parameter_stubs)[i]; |
| 1388 stub->ReplaceUsesWith(actual->definition()); | 1399 stub->ReplaceUsesWith(actual->definition()); |
| 1389 } | 1400 } |
| 1390 } | 1401 } |
| 1391 GrowableArray<Definition*>* defns = | 1402 GrowableArray<Definition*>* defns = |
| 1392 callee_graph->graph_entry()->initial_definitions(); | 1403 callee_graph->graph_entry()->initial_definitions(); |
| 1393 for (intptr_t i = 0; i < defns->length(); ++i) { | 1404 for (intptr_t i = 0; i < defns->length(); ++i) { |
| 1394 ConstantInstr* constant = (*defns)[i]->AsConstant(); | 1405 ConstantInstr* constant = (*defns)[i]->AsConstant(); |
| 1395 if ((constant != NULL) && constant->HasUses()) { | 1406 if ((constant != NULL) && constant->HasUses()) { |
| 1396 constant->ReplaceUsesWith( | 1407 constant->ReplaceUsesWith( |
| 1397 owner_->caller_graph()->GetConstant(constant->value())); | 1408 owner_->caller_graph()->GetConstant(constant->value())); |
| 1398 } | 1409 } |
| 1399 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); | 1410 CurrentContextInstr* context = (*defns)[i]->AsCurrentContext(); |
| 1400 if ((context != NULL) && context->HasUses()) { | 1411 if ((context != NULL) && context->HasUses()) { |
| 1401 ASSERT(call_data.call->IsClosureCall()); | 1412 ASSERT(call_data.call->IsClosureCall()); |
| 1402 LoadFieldInstr* context_load = new(isolate()) LoadFieldInstr( | 1413 LoadFieldInstr* context_load = new(Z) LoadFieldInstr( |
| 1403 new Value(redefinition), | 1414 new Value(redefinition), |
| 1404 Closure::context_offset(), | 1415 Closure::context_offset(), |
| 1405 AbstractType::ZoneHandle(isolate(), AbstractType::null()), | 1416 AbstractType::ZoneHandle(isolate(), AbstractType::null()), |
| 1406 call_data.call->token_pos()); | 1417 call_data.call->token_pos()); |
| 1407 context_load->set_is_immutable(true); | 1418 context_load->set_is_immutable(true); |
| 1408 context_load->set_ssa_temp_index( | 1419 context_load->set_ssa_temp_index( |
| 1409 owner_->caller_graph()->alloc_ssa_temp_index()); | 1420 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1410 context_load->InsertAfter(redefinition); | 1421 context_load->InsertAfter(redefinition); |
| 1411 context->ReplaceUsesWith(context_load); | 1422 context->ReplaceUsesWith(context_load); |
| 1412 } | 1423 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 1429 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, | 1440 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, |
| 1430 const Function& target) { | 1441 const Function& target) { |
| 1431 FlowGraphOptimizer optimizer(owner_->caller_graph()); | 1442 FlowGraphOptimizer optimizer(owner_->caller_graph()); |
| 1432 TargetEntryInstr* entry; | 1443 TargetEntryInstr* entry; |
| 1433 Definition* last; | 1444 Definition* last; |
| 1434 // Replace the receiver argument with a redefinition to prevent code from | 1445 // Replace the receiver argument with a redefinition to prevent code from |
| 1435 // the inlined body from being hoisted above the inlined entry. | 1446 // the inlined body from being hoisted above the inlined entry. |
| 1436 GrowableArray<Definition*> arguments(call_->ArgumentCount()); | 1447 GrowableArray<Definition*> arguments(call_->ArgumentCount()); |
| 1437 Definition* receiver = call_->ArgumentAt(0); | 1448 Definition* receiver = call_->ArgumentAt(0); |
| 1438 RedefinitionInstr* redefinition = | 1449 RedefinitionInstr* redefinition = |
| 1439 new(isolate()) RedefinitionInstr(new(isolate()) Value(receiver)); | 1450 new(Z) RedefinitionInstr(new(Z) Value(receiver)); |
| 1440 redefinition->set_ssa_temp_index( | 1451 redefinition->set_ssa_temp_index( |
| 1441 owner_->caller_graph()->alloc_ssa_temp_index()); | 1452 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1442 if (optimizer.TryInlineRecognizedMethod(receiver_cid, | 1453 if (optimizer.TryInlineRecognizedMethod(receiver_cid, |
| 1443 target, | 1454 target, |
| 1444 call_, | 1455 call_, |
| 1445 redefinition, | 1456 redefinition, |
| 1446 call_->instance_call()->token_pos(), | 1457 call_->instance_call()->token_pos(), |
| 1447 *call_->instance_call()->ic_data(), | 1458 *call_->instance_call()->ic_data(), |
| 1448 &entry, &last)) { | 1459 &entry, &last)) { |
| 1449 // Create a graph fragment. | 1460 // Create a graph fragment. |
| 1450 redefinition->InsertAfter(entry); | 1461 redefinition->InsertAfter(entry); |
| 1451 InlineExitCollector* exit_collector = | 1462 InlineExitCollector* exit_collector = |
| 1452 new(isolate()) InlineExitCollector(owner_->caller_graph(), call_); | 1463 new(Z) InlineExitCollector(owner_->caller_graph(), call_); |
| 1453 | 1464 |
| 1454 ReturnInstr* result = | 1465 ReturnInstr* result = |
| 1455 new(isolate()) ReturnInstr(call_->instance_call()->token_pos(), | 1466 new(Z) ReturnInstr(call_->instance_call()->token_pos(), |
| 1456 new(isolate()) Value(last)); | 1467 new(Z) Value(last)); |
| 1457 owner_->caller_graph()->AppendTo( | 1468 owner_->caller_graph()->AppendTo( |
| 1458 last, | 1469 last, |
| 1459 result, | 1470 result, |
| 1460 call_->env(), // Return can become deoptimization target. | 1471 call_->env(), // Return can become deoptimization target. |
| 1461 FlowGraph::kEffect); | 1472 FlowGraph::kEffect); |
| 1462 entry->set_last_instruction(result); | 1473 entry->set_last_instruction(result); |
| 1463 exit_collector->AddExit(result); | 1474 exit_collector->AddExit(result); |
| 1464 GraphEntryInstr* graph_entry = | 1475 GraphEntryInstr* graph_entry = |
| 1465 new(isolate()) GraphEntryInstr(NULL, // No parsed function. | 1476 new(Z) GraphEntryInstr(NULL, // No parsed function. |
| 1466 entry, | 1477 entry, |
| 1467 Isolate::kNoDeoptId); // No OSR id. | 1478 Isolate::kNoDeoptId); // No OSR id. |
| 1468 // Update polymorphic inliner state. | 1479 // Update polymorphic inliner state. |
| 1469 inlined_entries_.Add(graph_entry); | 1480 inlined_entries_.Add(graph_entry); |
| 1470 exit_collector_->Union(exit_collector); | 1481 exit_collector_->Union(exit_collector); |
| 1471 return true; | 1482 return true; |
| 1472 } | 1483 } |
| 1473 return false; | 1484 return false; |
| 1474 } | 1485 } |
| 1475 | 1486 |
| 1476 | 1487 |
| 1477 // Build a DAG to dispatch to the inlined function bodies. Load the class | 1488 // Build a DAG to dispatch to the inlined function bodies. Load the class |
| 1478 // id of the receiver and make explicit comparisons for each inlined body, | 1489 // id of the receiver and make explicit comparisons for each inlined body, |
| 1479 // in frequency order. If all variants are inlined, the entry to the last | 1490 // in frequency order. If all variants are inlined, the entry to the last |
| 1480 // inlined body is guarded by a CheckClassId instruction which can deopt. | 1491 // inlined body is guarded by a CheckClassId instruction which can deopt. |
| 1481 // If not all variants are inlined, we add a PolymorphicInstanceCall | 1492 // If not all variants are inlined, we add a PolymorphicInstanceCall |
| 1482 // instruction to handle the non-inlined variants. | 1493 // instruction to handle the non-inlined variants. |
| 1483 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { | 1494 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
| 1484 // Start with a fresh target entry. | 1495 // Start with a fresh target entry. |
| 1485 TargetEntryInstr* entry = | 1496 TargetEntryInstr* entry = |
| 1486 new(isolate()) TargetEntryInstr( | 1497 new(Z) TargetEntryInstr( |
| 1487 owner_->caller_graph()->allocate_block_id(), | 1498 owner_->caller_graph()->allocate_block_id(), |
| 1488 call_->GetBlock()->try_index()); | 1499 call_->GetBlock()->try_index()); |
| 1489 entry->InheritDeoptTarget(isolate(), call_); | 1500 entry->InheritDeoptTarget(isolate(), call_); |
| 1490 | 1501 |
| 1491 // This function uses a cursor (a pointer to the 'current' instruction) to | 1502 // This function uses a cursor (a pointer to the 'current' instruction) to |
| 1492 // build the graph. The next instruction will be inserted after the | 1503 // build the graph. The next instruction will be inserted after the |
| 1493 // cursor. | 1504 // cursor. |
| 1494 TargetEntryInstr* current_block = entry; | 1505 TargetEntryInstr* current_block = entry; |
| 1495 Instruction* cursor = entry; | 1506 Instruction* cursor = entry; |
| 1496 | 1507 |
| 1497 Definition* receiver = call_->ArgumentAt(0); | 1508 Definition* receiver = call_->ArgumentAt(0); |
| 1498 // There are at least two variants including non-inlined ones, so we have | 1509 // There are at least two variants including non-inlined ones, so we have |
| 1499 // at least one branch on the class id. | 1510 // at least one branch on the class id. |
| 1500 LoadClassIdInstr* load_cid = | 1511 LoadClassIdInstr* load_cid = |
| 1501 new(isolate()) LoadClassIdInstr(new(isolate()) Value(receiver)); | 1512 new(Z) LoadClassIdInstr(new(Z) Value(receiver)); |
| 1502 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); | 1513 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1503 cursor = AppendInstruction(cursor, load_cid); | 1514 cursor = AppendInstruction(cursor, load_cid); |
| 1504 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1515 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
| 1505 // 1. Guard the body with a class id check. | 1516 // 1. Guard the body with a class id check. |
| 1506 if ((i == (inlined_variants_.length() - 1)) && | 1517 if ((i == (inlined_variants_.length() - 1)) && |
| 1507 non_inlined_variants_.is_empty()) { | 1518 non_inlined_variants_.is_empty()) { |
| 1508 // If it is the last variant use a check class id instruction which can | 1519 // If it is the last variant use a check class id instruction which can |
| 1509 // deoptimize, followed unconditionally by the body. | 1520 // deoptimize, followed unconditionally by the body. |
| 1510 RedefinitionInstr* cid_redefinition = | 1521 RedefinitionInstr* cid_redefinition = |
| 1511 new RedefinitionInstr(new(isolate()) Value(load_cid)); | 1522 new RedefinitionInstr(new(Z) Value(load_cid)); |
| 1512 cid_redefinition->set_ssa_temp_index( | 1523 cid_redefinition->set_ssa_temp_index( |
| 1513 owner_->caller_graph()->alloc_ssa_temp_index()); | 1524 owner_->caller_graph()->alloc_ssa_temp_index()); |
| 1514 cursor = AppendInstruction(cursor, cid_redefinition); | 1525 cursor = AppendInstruction(cursor, cid_redefinition); |
| 1515 CheckClassIdInstr* check_class_id = new(isolate()) CheckClassIdInstr( | 1526 CheckClassIdInstr* check_class_id = new(Z) CheckClassIdInstr( |
| 1516 new(isolate()) Value(cid_redefinition), | 1527 new(Z) Value(cid_redefinition), |
| 1517 inlined_variants_[i].cid, | 1528 inlined_variants_[i].cid, |
| 1518 call_->deopt_id()); | 1529 call_->deopt_id()); |
| 1519 check_class_id->InheritDeoptTarget(isolate(), call_); | 1530 check_class_id->InheritDeoptTarget(isolate(), call_); |
| 1520 cursor = AppendInstruction(cursor, check_class_id); | 1531 cursor = AppendInstruction(cursor, check_class_id); |
| 1521 | 1532 |
| 1522 // The next instruction is the first instruction of the inlined body. | 1533 // The next instruction is the first instruction of the inlined body. |
| 1523 // Handle the two possible cases (unshared and shared subsequent | 1534 // Handle the two possible cases (unshared and shared subsequent |
| 1524 // predecessors) separately. | 1535 // predecessors) separately. |
| 1525 BlockEntryInstr* callee_entry = inlined_entries_[i]; | 1536 BlockEntryInstr* callee_entry = inlined_entries_[i]; |
| 1526 if (callee_entry->IsGraphEntry()) { | 1537 if (callee_entry->IsGraphEntry()) { |
| (...skipping 288 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1815 | 1826 |
| 1816 | 1827 |
| 1817 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { | 1828 intptr_t FlowGraphInliner::NextInlineId(const Function& function) { |
| 1818 const intptr_t id = inline_id_to_function_->length(); | 1829 const intptr_t id = inline_id_to_function_->length(); |
| 1819 inline_id_to_function_->Add(&function); | 1830 inline_id_to_function_->Add(&function); |
| 1820 return id; | 1831 return id; |
| 1821 } | 1832 } |
| 1822 | 1833 |
| 1823 | 1834 |
| 1824 } // namespace dart | 1835 } // namespace dart |
| OLD | NEW |