Chromium Code Reviews| 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 335 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 346 } | 346 } |
| 347 | 347 |
| 348 // Abort if this function has deoptimized too much. | 348 // Abort if this function has deoptimized too much. |
| 349 if (function.deoptimization_counter() >= | 349 if (function.deoptimization_counter() >= |
| 350 FLAG_deoptimization_counter_threshold) { | 350 FLAG_deoptimization_counter_threshold) { |
| 351 function.set_is_inlinable(false); | 351 function.set_is_inlinable(false); |
| 352 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 352 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 353 return false; | 353 return false; |
| 354 } | 354 } |
| 355 | 355 |
| 356 if (!ShouldWeInline(call->GetBlock()->loop_depth(), | |
| 357 function.optimized_instruction_count(), | |
| 358 function.optimized_call_site_count(), | |
| 359 CountConstants(*arguments))) { | |
| 360 TRACE_INLINING(OS::Print(" Bailout: early heuristics\n")); | |
|
srdjan
2012/12/13 19:00:17
Maybe print also the arguments that led to inlinin
Vyacheslav Egorov (Google)
2012/12/13 19:14:11
Done.
| |
| 361 return false; | |
| 362 } | |
| 363 | |
| 356 // Abort if this is a recursive occurrence. | 364 // Abort if this is a recursive occurrence. |
| 357 if (IsCallRecursive(function, call)) { | 365 if (IsCallRecursive(function, call)) { |
| 358 function.set_is_inlinable(false); | 366 function.set_is_inlinable(false); |
| 359 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 367 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 360 return false; | 368 return false; |
| 361 } | 369 } |
| 362 | 370 |
| 363 // Abort if the callee has an intrinsic translation. | 371 // Abort if the callee has an intrinsic translation. |
| 364 if (Intrinsifier::CanIntrinsify(function)) { | 372 if (Intrinsifier::CanIntrinsify(function)) { |
| 365 function.set_is_inlinable(false); | 373 function.set_is_inlinable(false); |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 390 } | 398 } |
| 391 | 399 |
| 392 // Load IC data for the callee. | 400 // Load IC data for the callee. |
| 393 if (function.HasCode()) { | 401 if (function.HasCode()) { |
| 394 const Code& unoptimized_code = | 402 const Code& unoptimized_code = |
| 395 Code::Handle(function.unoptimized_code()); | 403 Code::Handle(function.unoptimized_code()); |
| 396 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); | 404 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); |
| 397 } | 405 } |
| 398 | 406 |
| 399 // Build the callee graph. | 407 // Build the callee graph. |
| 400 const intptr_t loop_depth = call->GetBlock()->loop_depth(); | 408 const intptr_t loop_depth = call->GetBlock()->loop_depth(); |
|
Kevin Millikin (Google)
2012/12/13 16:43:40
Move this above the first call to ShouldWeInline.
Vyacheslav Egorov (Google)
2012/12/13 18:54:46
Done.
| |
| 401 FlowGraphBuilder builder(*parsed_function); | 409 FlowGraphBuilder builder(*parsed_function); |
| 402 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 410 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 403 FlowGraph* callee_graph; | 411 FlowGraph* callee_graph; |
| 404 { | 412 { |
| 405 TimerScope timer(FLAG_compiler_stats, | 413 TimerScope timer(FLAG_compiler_stats, |
| 406 &CompilerStats::graphinliner_build_timer, | 414 &CompilerStats::graphinliner_build_timer, |
| 407 isolate); | 415 isolate); |
| 408 callee_graph = | 416 callee_graph = |
| 409 builder.BuildGraph(FlowGraphBuilder::kValueContext, loop_depth); | 417 builder.BuildGraph(FlowGraphBuilder::kValueContext, loop_depth); |
| 410 } | 418 } |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 468 | 476 |
| 469 if (FLAG_trace_inlining && FLAG_print_flow_graph) { | 477 if (FLAG_trace_inlining && FLAG_print_flow_graph) { |
| 470 OS::Print("Callee graph for inlining %s\n", | 478 OS::Print("Callee graph for inlining %s\n", |
| 471 function.ToFullyQualifiedCString()); | 479 function.ToFullyQualifiedCString()); |
| 472 FlowGraphPrinter printer(*callee_graph); | 480 FlowGraphPrinter printer(*callee_graph); |
| 473 printer.PrintBlocks(); | 481 printer.PrintBlocks(); |
| 474 } | 482 } |
| 475 | 483 |
| 476 // Collect information about the call site and caller graph. | 484 // Collect information about the call site and caller graph. |
| 477 // TODO(zerny): Do this after CP and dead code elimination. | 485 // TODO(zerny): Do this after CP and dead code elimination. |
| 478 intptr_t constants_count = 0; | 486 intptr_t constants_count = 0; |
|
Kevin Millikin (Google)
2012/12/13 16:43:40
There's no reason to count this again, is there?
Vyacheslav Egorov (Google)
2012/12/13 18:54:46
Actually the count above is just an approximation
| |
| 479 for (intptr_t i = 0; i < param_stubs.length(); ++i) { | 487 for (intptr_t i = 0; i < param_stubs.length(); ++i) { |
| 480 if (param_stubs[i]->IsConstant()) ++constants_count; | 488 if (param_stubs[i]->IsConstant()) ++constants_count; |
| 481 } | 489 } |
| 482 GraphInfoCollector info; | 490 GraphInfoCollector info; |
| 483 info.Collect(*callee_graph); | 491 info.Collect(*callee_graph); |
| 484 const intptr_t size = info.instruction_count(); | 492 const intptr_t size = info.instruction_count(); |
| 485 // Use heuristics do decide if this call should be inlined. | 493 // Use heuristics do decide if this call should be inlined. |
| 486 if (!ShouldWeInline(loop_depth, | 494 if (!ShouldWeInline(loop_depth, |
|
Kevin Millikin (Google)
2012/12/13 16:43:40
It seems strange to call this twice? Is it needed
Vyacheslav Egorov (Google)
2012/12/13 18:54:46
Yes. Sometimes we attempt to inline big function t
| |
| 487 size, | 495 size, |
| 488 info.call_site_count(), | 496 info.call_site_count(), |
| 489 constants_count)) { | 497 constants_count)) { |
| 490 // If size is larger than all thresholds, don't consider it again. | 498 // If size is larger than all thresholds, don't consider it again. |
| 491 if ((size > FLAG_inlining_size_threshold) && | 499 if ((size > FLAG_inlining_size_threshold) && |
| 492 (size > FLAG_inlining_in_loop_size_threshold) && | 500 (size > FLAG_inlining_in_loop_size_threshold) && |
| 493 (size > FLAG_inlining_callee_call_sites_threshold) && | 501 (size > FLAG_inlining_callee_call_sites_threshold) && |
| 494 (size > FLAG_inlining_constant_arguments_size_threshold)) { | 502 (size > FLAG_inlining_constant_arguments_size_threshold)) { |
| 495 function.set_is_inlinable(false); | 503 function.set_is_inlinable(false); |
| 496 } | 504 } |
| 505 function.set_optimized_instruction_count(size); | |
|
Kevin Millikin (Google)
2012/12/13 16:43:40
Also a bit strange to set this only when we decide
Vyacheslav Egorov (Google)
2012/12/13 18:54:46
Yep, this is wrong.
| |
| 506 function.set_optimized_call_site_count(info.call_site_count()); | |
| 497 isolate->set_long_jump_base(base); | 507 isolate->set_long_jump_base(base); |
| 498 isolate->set_deopt_id(prev_deopt_id); | 508 isolate->set_deopt_id(prev_deopt_id); |
| 499 isolate->set_ic_data_array(prev_ic_data.raw()); | 509 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 500 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 510 TRACE_INLINING(OS::Print(" Bailout: heuristics with " |
| 501 "loop depth: %"Pd", " | 511 "loop depth: %"Pd", " |
| 502 "code size: %"Pd", " | 512 "code size: %"Pd", " |
| 503 "call sites: %"Pd", " | 513 "call sites: %"Pd", " |
| 504 "const args: %"Pd"\n", | 514 "const args: %"Pd"\n", |
| 505 loop_depth, | 515 loop_depth, |
| 506 size, | 516 size, |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 573 error = isolate->object_store()->sticky_error(); | 583 error = isolate->object_store()->sticky_error(); |
| 574 isolate->object_store()->clear_sticky_error(); | 584 isolate->object_store()->clear_sticky_error(); |
| 575 isolate->set_long_jump_base(base); | 585 isolate->set_long_jump_base(base); |
| 576 isolate->set_deopt_id(prev_deopt_id); | 586 isolate->set_deopt_id(prev_deopt_id); |
| 577 isolate->set_ic_data_array(prev_ic_data.raw()); | 587 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 578 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 588 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 579 return false; | 589 return false; |
| 580 } | 590 } |
| 581 } | 591 } |
| 582 | 592 |
| 593 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { | |
| 594 intptr_t count = 0; | |
| 595 for (intptr_t i = 0; i < arguments.length(); i++) { | |
| 596 if (arguments[i]->BindsToConstant()) count++; | |
| 597 } | |
| 598 return count; | |
| 599 } | |
| 600 | |
| 583 // Parse a function reusing the cache if possible. | 601 // Parse a function reusing the cache if possible. |
| 584 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 602 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| 585 // TODO(zerny): Use a hash map for the cache. | 603 // TODO(zerny): Use a hash map for the cache. |
| 586 for (intptr_t i = 0; i < function_cache_.length(); ++i) { | 604 for (intptr_t i = 0; i < function_cache_.length(); ++i) { |
| 587 ParsedFunction* parsed_function = function_cache_[i]; | 605 ParsedFunction* parsed_function = function_cache_[i]; |
| 588 if (parsed_function->function().raw() == function.raw()) { | 606 if (parsed_function->function().raw() == function.raw()) { |
| 589 *in_cache = true; | 607 *in_cache = true; |
| 590 SourceLabelResetter reset; | 608 SourceLabelResetter reset; |
| 591 parsed_function->node_sequence()->Visit(&reset); | 609 parsed_function->node_sequence()->Visit(&reset); |
| 592 return parsed_function; | 610 return parsed_function; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 762 intptr_t inlined_size_; | 780 intptr_t inlined_size_; |
| 763 intptr_t inlining_depth_; | 781 intptr_t inlining_depth_; |
| 764 CallSites* collected_call_sites_; | 782 CallSites* collected_call_sites_; |
| 765 CallSites* inlining_call_sites_; | 783 CallSites* inlining_call_sites_; |
| 766 GrowableArray<ParsedFunction*> function_cache_; | 784 GrowableArray<ParsedFunction*> function_cache_; |
| 767 | 785 |
| 768 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 786 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
| 769 }; | 787 }; |
| 770 | 788 |
| 771 | 789 |
| 790 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { | |
| 791 GraphInfoCollector info; | |
| 792 info.Collect(*flow_graph); | |
| 793 const Function& function = flow_graph->parsed_function().function(); | |
| 794 function.set_optimized_instruction_count( | |
| 795 static_cast<uint16_t>(info.instruction_count())); | |
| 796 function.set_optimized_call_site_count( | |
| 797 static_cast<uint16_t>(info.call_site_count())); | |
| 798 } | |
| 799 | |
| 800 | |
| 772 void FlowGraphInliner::Inline() { | 801 void FlowGraphInliner::Inline() { |
| 773 if ((FLAG_inlining_filter != NULL) && | 802 if ((FLAG_inlining_filter != NULL) && |
| 774 (strstr(flow_graph_-> | 803 (strstr(flow_graph_-> |
| 775 parsed_function().function().ToFullyQualifiedCString(), | 804 parsed_function().function().ToFullyQualifiedCString(), |
| 776 FLAG_inlining_filter) == NULL)) { | 805 FLAG_inlining_filter) == NULL)) { |
| 777 return; | 806 return; |
| 778 } | 807 } |
| 779 | 808 |
| 780 TRACE_INLINING(OS::Print( | 809 TRACE_INLINING(OS::Print( |
| 781 "Inlining calls in %s\n", | 810 "Inlining calls in %s\n", |
| (...skipping 17 matching lines...) Expand all Loading... | |
| 799 OS::Print("After Inlining of %s\n", flow_graph_-> | 828 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 800 parsed_function().function().ToFullyQualifiedCString()); | 829 parsed_function().function().ToFullyQualifiedCString()); |
| 801 FlowGraphPrinter printer(*flow_graph_); | 830 FlowGraphPrinter printer(*flow_graph_); |
| 802 printer.PrintBlocks(); | 831 printer.PrintBlocks(); |
| 803 } | 832 } |
| 804 } | 833 } |
| 805 } | 834 } |
| 806 } | 835 } |
| 807 | 836 |
| 808 } // namespace dart | 837 } // namespace dart |
| OLD | NEW |