| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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/compiler.h" | 7 #include "vm/compiler.h" |
| 8 #include "vm/flags.h" | 8 #include "vm/flags.h" |
| 9 #include "vm/flow_graph.h" | 9 #include "vm/flow_graph.h" |
| 10 #include "vm/flow_graph_builder.h" | 10 #include "vm/flow_graph_builder.h" |
| (...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 192 | 192 |
| 193 DISALLOW_COPY_AND_ASSIGN(CallSites); | 193 DISALLOW_COPY_AND_ASSIGN(CallSites); |
| 194 }; | 194 }; |
| 195 | 195 |
| 196 | 196 |
| 197 class CallSiteInliner : public ValueObject { | 197 class CallSiteInliner : public ValueObject { |
| 198 public: | 198 public: |
| 199 explicit CallSiteInliner(FlowGraph* flow_graph) | 199 explicit CallSiteInliner(FlowGraph* flow_graph) |
| 200 : caller_graph_(flow_graph), | 200 : caller_graph_(flow_graph), |
| 201 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), | 201 next_ssa_temp_index_(flow_graph->max_virtual_register_number()), |
| 202 inlined_(false), | |
| 203 initial_size_(flow_graph->InstructionCount()), | 202 initial_size_(flow_graph->InstructionCount()), |
| 204 inlined_size_(0), | 203 inlined_size_(0), |
| 205 inlining_depth_(1), | 204 inlining_depth_(1), |
| 206 collected_call_sites_(NULL), | 205 collected_call_sites_(NULL), |
| 207 inlining_call_sites_(NULL), | 206 inlining_call_sites_(NULL), |
| 208 function_cache_() { } | 207 function_cache_() { } |
| 209 | 208 |
| 210 void InlineCalls() { | 209 void InlineCalls() { |
| 211 // If inlining depth is less then one abort. | 210 // If inlining depth is less then one abort. |
| 212 if (FLAG_inlining_depth_threshold < 1) return; | 211 if (FLAG_inlining_depth_threshold < 1) return; |
| (...skipping 16 matching lines...) Expand all Loading... |
| 229 InlineStaticCalls(); | 228 InlineStaticCalls(); |
| 230 InlineClosureCalls(); | 229 InlineClosureCalls(); |
| 231 InlineInstanceCalls(); | 230 InlineInstanceCalls(); |
| 232 // Increment the inlining depth. Checked before recursive inlining. | 231 // Increment the inlining depth. Checked before recursive inlining. |
| 233 ++inlining_depth_; | 232 ++inlining_depth_; |
| 234 } | 233 } |
| 235 collected_call_sites_ = NULL; | 234 collected_call_sites_ = NULL; |
| 236 inlining_call_sites_ = NULL; | 235 inlining_call_sites_ = NULL; |
| 237 } | 236 } |
| 238 | 237 |
| 239 bool inlined() const { return inlined_; } | 238 intptr_t inlined_instructions() const { return inlined_size_; } |
| 240 | |
| 241 double GrowthFactor() const { | |
| 242 return static_cast<double>(inlined_size_) / | |
| 243 static_cast<double>(initial_size_); | |
| 244 } | |
| 245 | 239 |
| 246 private: | 240 private: |
| 247 bool TryInlining(const Function& function, | 241 bool TryInlining(const Function& function, |
| 248 const Array& argument_names, | 242 const Array& argument_names, |
| 249 GrowableArray<Value*>* arguments, | 243 GrowableArray<Value*>* arguments, |
| 250 Definition* call) { | 244 Definition* call) { |
| 251 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 245 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", |
| 252 function.ToCString(), | 246 function.ToCString(), |
| 253 function.deoptimization_counter())); | 247 function.deoptimization_counter())); |
| 254 | 248 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 387 | 381 |
| 388 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 382 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 389 OS::Print("Callee graph for inlining %s\n", | 383 OS::Print("Callee graph for inlining %s\n", |
| 390 function.ToFullyQualifiedCString()); | 384 function.ToFullyQualifiedCString()); |
| 391 FlowGraphPrinter printer(*callee_graph); | 385 FlowGraphPrinter printer(*callee_graph); |
| 392 printer.PrintBlocks(); | 386 printer.PrintBlocks(); |
| 393 } | 387 } |
| 394 | 388 |
| 395 // If result is more than size threshold then abort. | 389 // If result is more than size threshold then abort. |
| 396 // TODO(zerny): Do this after CP and dead code elimination. | 390 // TODO(zerny): Do this after CP and dead code elimination. |
| 397 intptr_t size = callee_graph->InstructionCount(); | 391 const intptr_t size = callee_graph->InstructionCount(); |
| 398 if (size > FLAG_inlining_size_threshold) { | 392 if (size > FLAG_inlining_size_threshold) { |
| 399 function.set_is_inlinable(false); | 393 function.set_is_inlinable(false); |
| 400 isolate->set_long_jump_base(base); | 394 isolate->set_long_jump_base(base); |
| 401 isolate->set_deopt_id(prev_deopt_id); | 395 isolate->set_deopt_id(prev_deopt_id); |
| 402 isolate->set_ic_data_array(prev_ic_data.raw()); | 396 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 403 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size)); | 397 TRACE_INLINING(OS::Print(" Bailout: graph size %"Pd"\n", size)); |
| 404 return false; | 398 return false; |
| 405 } | 399 } |
| 406 | 400 |
| 407 // If depth is less or equal to threshold recursively add call sites. | 401 // If depth is less or equal to threshold recursively add call sites. |
| 408 if (inlining_depth_ < FLAG_inlining_depth_threshold) { | 402 if (inlining_depth_ < FLAG_inlining_depth_threshold) { |
| 409 collected_call_sites_->FindCallSites(callee_graph); | 403 collected_call_sites_->FindCallSites(callee_graph); |
| 410 } | 404 } |
| 411 | 405 |
| 412 { | 406 { |
| 413 TimerScope timer(FLAG_compiler_stats, | 407 TimerScope timer(FLAG_compiler_stats, |
| 414 &CompilerStats::graphinliner_subst_timer, | 408 &CompilerStats::graphinliner_subst_timer, |
| 415 isolate); | 409 isolate); |
| 416 | 410 |
| 417 // Plug result in the caller graph. | 411 // Plug result in the caller graph. |
| 418 caller_graph_->InlineCall(call, callee_graph); | 412 caller_graph_->InlineCall(call, callee_graph); |
| 419 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); | 413 next_ssa_temp_index_ = caller_graph_->max_virtual_register_number(); |
| 420 | 414 |
| 421 // Remove push arguments of the call. | |
| 422 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 423 PushArgumentInstr* push = call->ArgumentAt(i); | |
| 424 push->ReplaceUsesWith(push->value()->definition()); | |
| 425 push->RemoveFromGraph(); | |
| 426 } | |
| 427 | |
| 428 // Replace each stub with the actual argument or the caller's constant. | 415 // Replace each stub with the actual argument or the caller's constant. |
| 429 // Nulls denote optional parameters for which no actual was given. | 416 // Nulls denote optional parameters for which no actual was given. |
| 430 for (intptr_t i = 0; i < arguments->length(); ++i) { | 417 for (intptr_t i = 0; i < arguments->length(); ++i) { |
| 431 Definition* stub = param_stubs[i]; | 418 Definition* stub = param_stubs[i]; |
| 432 Value* actual = (*arguments)[i]; | 419 Value* actual = (*arguments)[i]; |
| 433 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); | 420 if (actual != NULL) stub->ReplaceUsesWith(actual->definition()); |
| 434 } | 421 } |
| 435 | |
| 436 // Replace remaining constants with uses by constants in the caller's | |
| 437 // initial definitions. | |
| 438 GrowableArray<Definition*>* defns = | |
| 439 callee_graph->graph_entry()->initial_definitions(); | |
| 440 for (intptr_t i = 0; i < defns->length(); ++i) { | |
| 441 ConstantInstr* constant = (*defns)[i]->AsConstant(); | |
| 442 if (constant == NULL || | |
| 443 ((constant->input_use_list() == NULL) && | |
| 444 (constant->env_use_list() == NULL))) { | |
| 445 continue; | |
| 446 } | |
| 447 constant->ReplaceUsesWith( | |
| 448 caller_graph_->AddConstantToInitialDefinitions(constant->value())); | |
| 449 } | |
| 450 } | 422 } |
| 451 | 423 |
| 452 TRACE_INLINING(OS::Print(" Success\n")); | 424 TRACE_INLINING(OS::Print( |
| 425 " Success (inlined %"Pd" instructions)\n", size)); |
| 453 | 426 |
| 454 // Add the function to the cache. | 427 // Add the function to the cache. |
| 455 if (!in_cache) function_cache_.Add(parsed_function); | 428 if (!in_cache) function_cache_.Add(parsed_function); |
| 456 | 429 |
| 457 // Check that inlining maintains use lists. | 430 // Check that inlining maintains use lists. |
| 458 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->ValidateUseLists()); | 431 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph_->ValidateUseLists()); |
| 459 | 432 |
| 460 // Build succeeded so we restore the bailout jump. | 433 // Build succeeded so we restore the bailout jump. |
| 461 inlined_ = true; | |
| 462 inlined_size_ += size; | 434 inlined_size_ += size; |
| 463 isolate->set_long_jump_base(base); | 435 isolate->set_long_jump_base(base); |
| 464 isolate->set_deopt_id(prev_deopt_id); | 436 isolate->set_deopt_id(prev_deopt_id); |
| 465 isolate->set_ic_data_array(prev_ic_data.raw()); | 437 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 466 return true; | 438 return true; |
| 467 } else { | 439 } else { |
| 468 Error& error = Error::Handle(); | 440 Error& error = Error::Handle(); |
| 469 error = isolate->object_store()->sticky_error(); | 441 error = isolate->object_store()->sticky_error(); |
| 470 isolate->object_store()->clear_sticky_error(); | 442 isolate->object_store()->clear_sticky_error(); |
| 471 isolate->set_long_jump_base(base); | 443 isolate->set_long_jump_base(base); |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 647 } else { | 619 } else { |
| 648 param_stubs->Add( | 620 param_stubs->Add( |
| 649 GetDefaultValue(i - fixed_param_count, parsed_function)); | 621 GetDefaultValue(i - fixed_param_count, parsed_function)); |
| 650 } | 622 } |
| 651 } | 623 } |
| 652 } | 624 } |
| 653 | 625 |
| 654 | 626 |
| 655 FlowGraph* caller_graph_; | 627 FlowGraph* caller_graph_; |
| 656 intptr_t next_ssa_temp_index_; | 628 intptr_t next_ssa_temp_index_; |
| 657 bool inlined_; | |
| 658 intptr_t initial_size_; | 629 intptr_t initial_size_; |
| 659 intptr_t inlined_size_; | 630 intptr_t inlined_size_; |
| 660 intptr_t inlining_depth_; | 631 intptr_t inlining_depth_; |
| 661 CallSites* collected_call_sites_; | 632 CallSites* collected_call_sites_; |
| 662 CallSites* inlining_call_sites_; | 633 CallSites* inlining_call_sites_; |
| 663 GrowableArray<ParsedFunction*> function_cache_; | 634 GrowableArray<ParsedFunction*> function_cache_; |
| 664 | 635 |
| 665 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 636 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
| 666 }; | 637 }; |
| 667 | 638 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 681 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 652 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 682 OS::Print("Before Inlining of %s\n", flow_graph_-> | 653 OS::Print("Before Inlining of %s\n", flow_graph_-> |
| 683 parsed_function().function().ToFullyQualifiedCString()); | 654 parsed_function().function().ToFullyQualifiedCString()); |
| 684 FlowGraphPrinter printer(*flow_graph_); | 655 FlowGraphPrinter printer(*flow_graph_); |
| 685 printer.PrintBlocks(); | 656 printer.PrintBlocks(); |
| 686 } | 657 } |
| 687 | 658 |
| 688 CallSiteInliner inliner(flow_graph_); | 659 CallSiteInliner inliner(flow_graph_); |
| 689 inliner.InlineCalls(); | 660 inliner.InlineCalls(); |
| 690 | 661 |
| 691 if (inliner.inlined()) { | 662 if (inliner.inlined_instructions() > 0) { |
| 692 flow_graph_->RepairGraphAfterInlining(); | 663 flow_graph_->RepairGraphAfterInlining(); |
| 693 if (FLAG_trace_inlining) { | 664 if (FLAG_trace_inlining) { |
| 694 OS::Print("Inlining growth factor: %f\n", inliner.GrowthFactor()); | 665 OS::Print("Inlined %"Pd" instructions\n", inliner.inlined_instructions()); |
| 695 if (FLAG_print_flow_graph) { | 666 if (FLAG_print_flow_graph) { |
| 696 OS::Print("After Inlining of %s\n", flow_graph_-> | 667 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 697 parsed_function().function().ToFullyQualifiedCString()); | 668 parsed_function().function().ToFullyQualifiedCString()); |
| 698 FlowGraphPrinter printer(*flow_graph_); | 669 FlowGraphPrinter printer(*flow_graph_); |
| 699 printer.PrintBlocks(); | 670 printer.PrintBlocks(); |
| 700 } | 671 } |
| 701 } | 672 } |
| 702 } | 673 } |
| 703 } | 674 } |
| 704 | 675 |
| 705 } // namespace dart | 676 } // namespace dart |
| OLD | NEW |