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 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
375 | 375 |
376 GrowableArray<CidTarget> inlined_variants_; | 376 GrowableArray<CidTarget> inlined_variants_; |
377 GrowableArray<CidTarget> non_inlined_variants_; | 377 GrowableArray<CidTarget> non_inlined_variants_; |
378 GrowableArray<BlockEntryInstr*> inlined_entries_; | 378 GrowableArray<BlockEntryInstr*> inlined_entries_; |
379 InlineExitCollector* exit_collector_; | 379 InlineExitCollector* exit_collector_; |
380 }; | 380 }; |
381 | 381 |
382 | 382 |
383 class CallSiteInliner : public ValueObject { | 383 class CallSiteInliner : public ValueObject { |
384 public: | 384 public: |
385 CallSiteInliner(FlowGraph* flow_graph, | 385 explicit CallSiteInliner(FlowGraph* flow_graph) |
386 GrowableArray<const Field*>* guarded_fields) | |
387 : caller_graph_(flow_graph), | 386 : caller_graph_(flow_graph), |
388 inlined_(false), | 387 inlined_(false), |
389 initial_size_(flow_graph->InstructionCount()), | 388 initial_size_(flow_graph->InstructionCount()), |
390 inlined_size_(0), | 389 inlined_size_(0), |
391 inlining_depth_(1), | 390 inlining_depth_(1), |
392 collected_call_sites_(NULL), | 391 collected_call_sites_(NULL), |
393 inlining_call_sites_(NULL), | 392 inlining_call_sites_(NULL), |
394 function_cache_(), | 393 function_cache_() { } |
395 guarded_fields_(guarded_fields) { } | |
396 | 394 |
397 FlowGraph* caller_graph() const { return caller_graph_; } | 395 FlowGraph* caller_graph() const { return caller_graph_; } |
398 | 396 |
399 // Inlining heuristics based on Cooper et al. 2008. | 397 // Inlining heuristics based on Cooper et al. 2008. |
400 bool ShouldWeInline(const Function& callee, | 398 bool ShouldWeInline(const Function& callee, |
401 intptr_t instr_count, | 399 intptr_t instr_count, |
402 intptr_t call_site_count, | 400 intptr_t call_site_count, |
403 intptr_t const_arg_count) { | 401 intptr_t const_arg_count) { |
404 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { | 402 if (inlined_size_ > FLAG_inlining_caller_size_threshold) { |
405 // Prevent methods becoming humongous and thus slow to compile. | 403 // Prevent methods becoming humongous and thus slow to compile. |
(...skipping 131 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
537 Array& ic_data_array = Array::Handle(); | 535 Array& ic_data_array = Array::Handle(); |
538 if (function.HasCode()) { | 536 if (function.HasCode()) { |
539 const Code& unoptimized_code = | 537 const Code& unoptimized_code = |
540 Code::Handle(function.unoptimized_code()); | 538 Code::Handle(function.unoptimized_code()); |
541 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); | 539 ic_data_array = unoptimized_code.ExtractTypeFeedbackArray(); |
542 } | 540 } |
543 | 541 |
544 // Build the callee graph. | 542 // Build the callee graph. |
545 InlineExitCollector* exit_collector = | 543 InlineExitCollector* exit_collector = |
546 new InlineExitCollector(caller_graph_, call); | 544 new InlineExitCollector(caller_graph_, call); |
547 FlowGraphBuilder builder(parsed_function, | 545 GrowableArray<const Field*> inlined_guarded_fields; |
548 ic_data_array, | 546 FlowGraphBuilder* builder = new FlowGraphBuilder(parsed_function, |
549 exit_collector, | 547 ic_data_array, |
550 Isolate::kNoDeoptId); | 548 exit_collector, |
551 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 549 &inlined_guarded_fields, |
| 550 Isolate::kNoDeoptId); |
| 551 builder->SetInitialBlockId(caller_graph_->max_block_id()); |
552 FlowGraph* callee_graph; | 552 FlowGraph* callee_graph; |
553 { | 553 { |
554 TimerScope timer(FLAG_compiler_stats, | 554 TimerScope timer(FLAG_compiler_stats, |
555 &CompilerStats::graphinliner_build_timer, | 555 &CompilerStats::graphinliner_build_timer, |
556 isolate); | 556 isolate); |
557 callee_graph = builder.BuildGraph(); | 557 callee_graph = builder->BuildGraph(); |
558 } | 558 } |
559 | 559 |
560 // The parameter stubs are a copy of the actual arguments providing | 560 // The parameter stubs are a copy of the actual arguments providing |
561 // concrete information about the values, for example constant values, | 561 // concrete information about the values, for example constant values, |
562 // without linking between the caller and callee graphs. | 562 // without linking between the caller and callee graphs. |
563 // TODO(zerny): Put more information in the stubs, eg, type information. | 563 // TODO(zerny): Put more information in the stubs, eg, type information. |
564 ZoneGrowableArray<Definition*>* param_stubs = | 564 ZoneGrowableArray<Definition*>* param_stubs = |
565 new ZoneGrowableArray<Definition*>(function.NumParameters()); | 565 new ZoneGrowableArray<Definition*>(function.NumParameters()); |
566 | 566 |
567 // Create a parameter stub for each fixed positional parameter. | 567 // Create a parameter stub for each fixed positional parameter. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
600 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), | 600 callee_graph->ComputeSSA(caller_graph_->max_virtual_register_number(), |
601 param_stubs); | 601 param_stubs); |
602 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 602 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
603 } | 603 } |
604 | 604 |
605 { | 605 { |
606 TimerScope timer(FLAG_compiler_stats, | 606 TimerScope timer(FLAG_compiler_stats, |
607 &CompilerStats::graphinliner_opt_timer, | 607 &CompilerStats::graphinliner_opt_timer, |
608 isolate); | 608 isolate); |
609 // TODO(zerny): Do more optimization passes on the callee graph. | 609 // TODO(zerny): Do more optimization passes on the callee graph. |
610 FlowGraphOptimizer optimizer(callee_graph, guarded_fields_); | 610 FlowGraphOptimizer optimizer(callee_graph); |
611 optimizer.ApplyICData(); | 611 optimizer.ApplyICData(); |
612 DEBUG_ASSERT(callee_graph->VerifyUseLists()); | 612 DEBUG_ASSERT(callee_graph->VerifyUseLists()); |
613 } | 613 } |
614 | 614 |
615 if (FLAG_trace_inlining && | 615 if (FLAG_trace_inlining && |
616 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 616 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
617 OS::Print("Callee graph for inlining %s\n", | 617 OS::Print("Callee graph for inlining %s\n", |
618 function.ToFullyQualifiedCString()); | 618 function.ToFullyQualifiedCString()); |
619 FlowGraphPrinter printer(*callee_graph); | 619 FlowGraphPrinter printer(*callee_graph); |
620 printer.PrintBlocks(); | 620 printer.PrintBlocks(); |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 | 661 |
662 // Build succeeded so we restore the bailout jump. | 662 // Build succeeded so we restore the bailout jump. |
663 inlined_ = true; | 663 inlined_ = true; |
664 inlined_size_ += size; | 664 inlined_size_ += size; |
665 isolate->set_long_jump_base(base); | 665 isolate->set_long_jump_base(base); |
666 isolate->set_deopt_id(prev_deopt_id); | 666 isolate->set_deopt_id(prev_deopt_id); |
667 | 667 |
668 call_data->callee_graph = callee_graph; | 668 call_data->callee_graph = callee_graph; |
669 call_data->parameter_stubs = param_stubs; | 669 call_data->parameter_stubs = param_stubs; |
670 call_data->exit_collector = exit_collector; | 670 call_data->exit_collector = exit_collector; |
| 671 |
| 672 // When inlined, we add the guarded fields of the callee to the caller's |
| 673 // list of guarded fields. |
| 674 for (intptr_t i = 0; i < inlined_guarded_fields.length(); ++i) { |
| 675 caller_graph_->builder().AddToGuardedFields(*inlined_guarded_fields[i]); |
| 676 } |
| 677 |
671 TRACE_INLINING(OS::Print(" Success\n")); | 678 TRACE_INLINING(OS::Print(" Success\n")); |
672 return true; | 679 return true; |
673 } else { | 680 } else { |
674 Error& error = Error::Handle(); | 681 Error& error = Error::Handle(); |
675 error = isolate->object_store()->sticky_error(); | 682 error = isolate->object_store()->sticky_error(); |
676 isolate->object_store()->clear_sticky_error(); | 683 isolate->object_store()->clear_sticky_error(); |
677 isolate->set_long_jump_base(base); | 684 isolate->set_long_jump_base(base); |
678 isolate->set_deopt_id(prev_deopt_id); | 685 isolate->set_deopt_id(prev_deopt_id); |
679 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 686 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
680 return false; | 687 return false; |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
991 | 998 |
992 | 999 |
993 FlowGraph* caller_graph_; | 1000 FlowGraph* caller_graph_; |
994 bool inlined_; | 1001 bool inlined_; |
995 intptr_t initial_size_; | 1002 intptr_t initial_size_; |
996 intptr_t inlined_size_; | 1003 intptr_t inlined_size_; |
997 intptr_t inlining_depth_; | 1004 intptr_t inlining_depth_; |
998 CallSites* collected_call_sites_; | 1005 CallSites* collected_call_sites_; |
999 CallSites* inlining_call_sites_; | 1006 CallSites* inlining_call_sites_; |
1000 GrowableArray<ParsedFunction*> function_cache_; | 1007 GrowableArray<ParsedFunction*> function_cache_; |
1001 GrowableArray<const Field*>* guarded_fields_; | |
1002 | 1008 |
1003 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 1009 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
1004 }; | 1010 }; |
1005 | 1011 |
1006 | 1012 |
1007 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1013 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
1008 PolymorphicInstanceCallInstr* call) | 1014 PolymorphicInstanceCallInstr* call) |
1009 : owner_(owner), | 1015 : owner_(owner), |
1010 call_(call), | 1016 call_(call), |
1011 num_variants_(call->ic_data().NumberOfChecks()), | 1017 num_variants_(call->ic_data().NumberOfChecks()), |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1146 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1152 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
1147 Value* input = second->InputAt(i); | 1153 Value* input = second->InputAt(i); |
1148 input->definition()->AddInputUse(input); | 1154 input->definition()->AddInputUse(input); |
1149 } | 1155 } |
1150 first->LinkTo(second); | 1156 first->LinkTo(second); |
1151 return second; | 1157 return second; |
1152 } | 1158 } |
1153 | 1159 |
1154 | 1160 |
1155 bool PolymorphicInliner::TryInlineRecognizedMethod(const Function& target) { | 1161 bool PolymorphicInliner::TryInlineRecognizedMethod(const Function& target) { |
1156 FlowGraphOptimizer optimizer(owner_->caller_graph(), | 1162 FlowGraphOptimizer optimizer(owner_->caller_graph()); |
1157 NULL); // No guarded fields needed. | |
1158 TargetEntryInstr* entry; | 1163 TargetEntryInstr* entry; |
1159 Definition* last; | 1164 Definition* last; |
1160 if (optimizer.TryInlineRecognizedMethod(target, | 1165 if (optimizer.TryInlineRecognizedMethod(target, |
1161 call_, | 1166 call_, |
1162 call_->ic_data(), | 1167 call_->ic_data(), |
1163 &entry, &last)) { | 1168 &entry, &last)) { |
1164 // Create a graph fragment. | 1169 // Create a graph fragment. |
1165 InlineExitCollector* exit_collector = | 1170 InlineExitCollector* exit_collector = |
1166 new InlineExitCollector(owner_->caller_graph(), call_); | 1171 new InlineExitCollector(owner_->caller_graph(), call_); |
1167 | 1172 |
(...skipping 300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1468 flow_graph_->parsed_function().function().ToCString())); | 1473 flow_graph_->parsed_function().function().ToCString())); |
1469 | 1474 |
1470 if (FLAG_trace_inlining && | 1475 if (FLAG_trace_inlining && |
1471 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 1476 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
1472 OS::Print("Before Inlining of %s\n", flow_graph_-> | 1477 OS::Print("Before Inlining of %s\n", flow_graph_-> |
1473 parsed_function().function().ToFullyQualifiedCString()); | 1478 parsed_function().function().ToFullyQualifiedCString()); |
1474 FlowGraphPrinter printer(*flow_graph_); | 1479 FlowGraphPrinter printer(*flow_graph_); |
1475 printer.PrintBlocks(); | 1480 printer.PrintBlocks(); |
1476 } | 1481 } |
1477 | 1482 |
1478 CallSiteInliner inliner(flow_graph_, guarded_fields_); | 1483 CallSiteInliner inliner(flow_graph_); |
1479 inliner.InlineCalls(); | 1484 inliner.InlineCalls(); |
1480 | 1485 |
1481 if (inliner.inlined()) { | 1486 if (inliner.inlined()) { |
1482 flow_graph_->DiscoverBlocks(); | 1487 flow_graph_->DiscoverBlocks(); |
1483 if (FLAG_trace_inlining) { | 1488 if (FLAG_trace_inlining) { |
1484 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 1489 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); |
1485 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { | 1490 if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) { |
1486 OS::Print("After Inlining of %s\n", flow_graph_-> | 1491 OS::Print("After Inlining of %s\n", flow_graph_-> |
1487 parsed_function().function().ToFullyQualifiedCString()); | 1492 parsed_function().function().ToFullyQualifiedCString()); |
1488 FlowGraphPrinter printer(*flow_graph_); | 1493 FlowGraphPrinter printer(*flow_graph_); |
1489 printer.PrintBlocks(); | 1494 printer.PrintBlocks(); |
1490 } | 1495 } |
1491 } | 1496 } |
1492 } | 1497 } |
1493 } | 1498 } |
1494 | 1499 |
1495 } // namespace dart | 1500 } // namespace dart |
OLD | NEW |