| 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 const intptr_t loop_depth = call->GetBlock()->loop_depth(); |
| 357 const intptr_t constant_arguments = CountConstants(*arguments); |
| 358 if (!ShouldWeInline(loop_depth, |
| 359 function.optimized_instruction_count(), |
| 360 function.optimized_call_site_count(), |
| 361 constant_arguments)) { |
| 362 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 363 "loop depth: %"Pd", " |
| 364 "code size: %"Pd", " |
| 365 "call sites: %"Pd", " |
| 366 "const args: %"Pd"\n", |
| 367 loop_depth, |
| 368 function.optimized_instruction_count(), |
| 369 function.optimized_call_site_count(), |
| 370 constant_arguments)); |
| 371 return false; |
| 372 } |
| 373 |
| 356 // Abort if this is a recursive occurrence. | 374 // Abort if this is a recursive occurrence. |
| 357 if (IsCallRecursive(function, call)) { | 375 if (IsCallRecursive(function, call)) { |
| 358 function.set_is_inlinable(false); | 376 function.set_is_inlinable(false); |
| 359 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 377 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 360 return false; | 378 return false; |
| 361 } | 379 } |
| 362 | 380 |
| 363 // Abort if the callee has an intrinsic translation. | 381 // Abort if the callee has an intrinsic translation. |
| 364 if (Intrinsifier::CanIntrinsify(function)) { | 382 if (Intrinsifier::CanIntrinsify(function)) { |
| 365 function.set_is_inlinable(false); | 383 function.set_is_inlinable(false); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 390 } | 408 } |
| 391 | 409 |
| 392 // Load IC data for the callee. | 410 // Load IC data for the callee. |
| 393 if (function.HasCode()) { | 411 if (function.HasCode()) { |
| 394 const Code& unoptimized_code = | 412 const Code& unoptimized_code = |
| 395 Code::Handle(function.unoptimized_code()); | 413 Code::Handle(function.unoptimized_code()); |
| 396 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); | 414 isolate->set_ic_data_array(unoptimized_code.ExtractTypeFeedbackArray()); |
| 397 } | 415 } |
| 398 | 416 |
| 399 // Build the callee graph. | 417 // Build the callee graph. |
| 400 const intptr_t loop_depth = call->GetBlock()->loop_depth(); | |
| 401 FlowGraphBuilder builder(*parsed_function); | 418 FlowGraphBuilder builder(*parsed_function); |
| 402 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 419 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 403 FlowGraph* callee_graph; | 420 FlowGraph* callee_graph; |
| 404 { | 421 { |
| 405 TimerScope timer(FLAG_compiler_stats, | 422 TimerScope timer(FLAG_compiler_stats, |
| 406 &CompilerStats::graphinliner_build_timer, | 423 &CompilerStats::graphinliner_build_timer, |
| 407 isolate); | 424 isolate); |
| 408 callee_graph = | 425 callee_graph = |
| 409 builder.BuildGraph(FlowGraphBuilder::kValueContext, loop_depth); | 426 builder.BuildGraph(FlowGraphBuilder::kValueContext, loop_depth); |
| 410 } | 427 } |
| (...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 475 | 492 |
| 476 // Collect information about the call site and caller graph. | 493 // Collect information about the call site and caller graph. |
| 477 // TODO(zerny): Do this after CP and dead code elimination. | 494 // TODO(zerny): Do this after CP and dead code elimination. |
| 478 intptr_t constants_count = 0; | 495 intptr_t constants_count = 0; |
| 479 for (intptr_t i = 0; i < param_stubs.length(); ++i) { | 496 for (intptr_t i = 0; i < param_stubs.length(); ++i) { |
| 480 if (param_stubs[i]->IsConstant()) ++constants_count; | 497 if (param_stubs[i]->IsConstant()) ++constants_count; |
| 481 } | 498 } |
| 482 GraphInfoCollector info; | 499 GraphInfoCollector info; |
| 483 info.Collect(*callee_graph); | 500 info.Collect(*callee_graph); |
| 484 const intptr_t size = info.instruction_count(); | 501 const intptr_t size = info.instruction_count(); |
| 502 |
| 503 function.set_optimized_instruction_count(size); |
| 504 function.set_optimized_call_site_count(info.call_site_count()); |
| 505 |
| 485 // Use heuristics do decide if this call should be inlined. | 506 // Use heuristics do decide if this call should be inlined. |
| 486 if (!ShouldWeInline(loop_depth, | 507 if (!ShouldWeInline(loop_depth, |
| 487 size, | 508 size, |
| 488 info.call_site_count(), | 509 info.call_site_count(), |
| 489 constants_count)) { | 510 constants_count)) { |
| 490 // If size is larger than all thresholds, don't consider it again. | 511 // If size is larger than all thresholds, don't consider it again. |
| 491 if ((size > FLAG_inlining_size_threshold) && | 512 if ((size > FLAG_inlining_size_threshold) && |
| 492 (size > FLAG_inlining_in_loop_size_threshold) && | 513 (size > FLAG_inlining_in_loop_size_threshold) && |
| 493 (size > FLAG_inlining_callee_call_sites_threshold) && | 514 (size > FLAG_inlining_callee_call_sites_threshold) && |
| 494 (size > FLAG_inlining_constant_arguments_size_threshold)) { | 515 (size > FLAG_inlining_constant_arguments_size_threshold)) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 573 error = isolate->object_store()->sticky_error(); | 594 error = isolate->object_store()->sticky_error(); |
| 574 isolate->object_store()->clear_sticky_error(); | 595 isolate->object_store()->clear_sticky_error(); |
| 575 isolate->set_long_jump_base(base); | 596 isolate->set_long_jump_base(base); |
| 576 isolate->set_deopt_id(prev_deopt_id); | 597 isolate->set_deopt_id(prev_deopt_id); |
| 577 isolate->set_ic_data_array(prev_ic_data.raw()); | 598 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 578 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 599 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 579 return false; | 600 return false; |
| 580 } | 601 } |
| 581 } | 602 } |
| 582 | 603 |
| 604 static intptr_t CountConstants(const GrowableArray<Value*>& arguments) { |
| 605 intptr_t count = 0; |
| 606 for (intptr_t i = 0; i < arguments.length(); i++) { |
| 607 if (arguments[i]->BindsToConstant()) count++; |
| 608 } |
| 609 return count; |
| 610 } |
| 611 |
| 583 // Parse a function reusing the cache if possible. | 612 // Parse a function reusing the cache if possible. |
| 584 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { | 613 ParsedFunction* GetParsedFunction(const Function& function, bool* in_cache) { |
| 585 // TODO(zerny): Use a hash map for the cache. | 614 // TODO(zerny): Use a hash map for the cache. |
| 586 for (intptr_t i = 0; i < function_cache_.length(); ++i) { | 615 for (intptr_t i = 0; i < function_cache_.length(); ++i) { |
| 587 ParsedFunction* parsed_function = function_cache_[i]; | 616 ParsedFunction* parsed_function = function_cache_[i]; |
| 588 if (parsed_function->function().raw() == function.raw()) { | 617 if (parsed_function->function().raw() == function.raw()) { |
| 589 *in_cache = true; | 618 *in_cache = true; |
| 590 SourceLabelResetter reset; | 619 SourceLabelResetter reset; |
| 591 parsed_function->node_sequence()->Visit(&reset); | 620 parsed_function->node_sequence()->Visit(&reset); |
| 592 return parsed_function; | 621 return parsed_function; |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 762 intptr_t inlined_size_; | 791 intptr_t inlined_size_; |
| 763 intptr_t inlining_depth_; | 792 intptr_t inlining_depth_; |
| 764 CallSites* collected_call_sites_; | 793 CallSites* collected_call_sites_; |
| 765 CallSites* inlining_call_sites_; | 794 CallSites* inlining_call_sites_; |
| 766 GrowableArray<ParsedFunction*> function_cache_; | 795 GrowableArray<ParsedFunction*> function_cache_; |
| 767 | 796 |
| 768 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 797 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
| 769 }; | 798 }; |
| 770 | 799 |
| 771 | 800 |
| 801 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph) { |
| 802 GraphInfoCollector info; |
| 803 info.Collect(*flow_graph); |
| 804 const Function& function = flow_graph->parsed_function().function(); |
| 805 function.set_optimized_instruction_count( |
| 806 static_cast<uint16_t>(info.instruction_count())); |
| 807 function.set_optimized_call_site_count( |
| 808 static_cast<uint16_t>(info.call_site_count())); |
| 809 } |
| 810 |
| 811 |
| 772 void FlowGraphInliner::Inline() { | 812 void FlowGraphInliner::Inline() { |
| 813 // Collect graph info and store it on the function. |
| 814 // We might later use it for an early bailout from the inlining. |
| 815 CollectGraphInfo(flow_graph_); |
| 816 |
| 773 if ((FLAG_inlining_filter != NULL) && | 817 if ((FLAG_inlining_filter != NULL) && |
| 774 (strstr(flow_graph_-> | 818 (strstr(flow_graph_-> |
| 775 parsed_function().function().ToFullyQualifiedCString(), | 819 parsed_function().function().ToFullyQualifiedCString(), |
| 776 FLAG_inlining_filter) == NULL)) { | 820 FLAG_inlining_filter) == NULL)) { |
| 777 return; | 821 return; |
| 778 } | 822 } |
| 779 | 823 |
| 780 TRACE_INLINING(OS::Print( | 824 TRACE_INLINING(OS::Print( |
| 781 "Inlining calls in %s\n", | 825 "Inlining calls in %s\n", |
| 782 flow_graph_->parsed_function().function().ToCString())); | 826 flow_graph_->parsed_function().function().ToCString())); |
| (...skipping 16 matching lines...) Expand all Loading... |
| 799 OS::Print("After Inlining of %s\n", flow_graph_-> | 843 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 800 parsed_function().function().ToFullyQualifiedCString()); | 844 parsed_function().function().ToFullyQualifiedCString()); |
| 801 FlowGraphPrinter printer(*flow_graph_); | 845 FlowGraphPrinter printer(*flow_graph_); |
| 802 printer.PrintBlocks(); | 846 printer.PrintBlocks(); |
| 803 } | 847 } |
| 804 } | 848 } |
| 805 } | 849 } |
| 806 } | 850 } |
| 807 | 851 |
| 808 } // namespace dart | 852 } // namespace dart |
| OLD | NEW |