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