| 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/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" |
| 11 #include "vm/flow_graph_optimizer.h" | 11 #include "vm/flow_graph_optimizer.h" |
| 12 #include "vm/il_printer.h" | 12 #include "vm/il_printer.h" |
| 13 #include "vm/intrinsifier.h" | 13 #include "vm/intrinsifier.h" |
| 14 #include "vm/longjump.h" | 14 #include "vm/longjump.h" |
| 15 #include "vm/object.h" | 15 #include "vm/object.h" |
| 16 #include "vm/object_store.h" | 16 #include "vm/object_store.h" |
| 17 #include "vm/timer.h" | 17 #include "vm/timer.h" |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| 20 | 20 |
| 21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); | 21 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
| 22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); | 22 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
| 23 | 23 |
| 24 // Flags for inlining heuristics. | 24 // Flags for inlining heuristics. |
| 25 DEFINE_FLAG(int, inlining_depth_threshold, 3, | 25 DEFINE_FLAG(int, inlining_depth_threshold, 3, |
| 26 "Inline function calls up to threshold nesting depth"); | 26 "Inline function calls up to threshold nesting depth"); |
| 27 DEFINE_FLAG(int, inlining_size_threshold, 20, | 27 DEFINE_FLAG(int, inlining_size_threshold, 20, |
| 28 "Always inline functions that have threshold or fewer instructions"); | 28 "Always inline functions that have threshold or fewer instructions"); |
| 29 DEFINE_FLAG(int, inlining_in_loop_size_threshold, 80, | |
| 30 "Inline functions in loops that have threshold or fewer instructions"); | |
| 31 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1, | 29 DEFINE_FLAG(int, inlining_callee_call_sites_threshold, 1, |
| 32 "Always inline functions containing threshold or fewer calls."); | 30 "Always inline functions containing threshold or fewer calls."); |
| 33 DEFINE_FLAG(int, inlining_constant_arguments_count, 1, | 31 DEFINE_FLAG(int, inlining_constant_arguments_count, 1, |
| 34 "Inline function calls with sufficient constant arguments " | 32 "Inline function calls with sufficient constant arguments " |
| 35 "and up to the increased threshold on instructions"); | 33 "and up to the increased threshold on instructions"); |
| 36 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, | 34 DEFINE_FLAG(int, inlining_constant_arguments_size_threshold, 60, |
| 37 "Inline function calls with sufficient constant arguments " | 35 "Inline function calls with sufficient constant arguments " |
| 38 "and up to the increased threshold on instructions"); | 36 "and up to the increased threshold on instructions"); |
| 39 DEFINE_FLAG(int, inlining_hotness, 10, | 37 DEFINE_FLAG(int, inlining_hotness, 10, |
| 40 "Inline only hotter calls, in percents (0 .. 100); " | 38 "Inline only hotter calls, in percents (0 .. 100); " |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 296 : caller_graph_(flow_graph), | 294 : caller_graph_(flow_graph), |
| 297 inlined_(false), | 295 inlined_(false), |
| 298 initial_size_(flow_graph->InstructionCount()), | 296 initial_size_(flow_graph->InstructionCount()), |
| 299 inlined_size_(0), | 297 inlined_size_(0), |
| 300 inlining_depth_(1), | 298 inlining_depth_(1), |
| 301 collected_call_sites_(NULL), | 299 collected_call_sites_(NULL), |
| 302 inlining_call_sites_(NULL), | 300 inlining_call_sites_(NULL), |
| 303 function_cache_() { } | 301 function_cache_() { } |
| 304 | 302 |
| 305 // Inlining heuristics based on Cooper et al. 2008. | 303 // Inlining heuristics based on Cooper et al. 2008. |
| 306 bool ShouldWeInline(intptr_t loop_depth, | 304 bool ShouldWeInline(intptr_t instr_count, |
| 307 intptr_t instr_count, | |
| 308 intptr_t call_site_count, | 305 intptr_t call_site_count, |
| 309 intptr_t const_arg_count) { | 306 intptr_t const_arg_count) { |
| 310 if (instr_count <= FLAG_inlining_size_threshold) { | 307 if (instr_count <= FLAG_inlining_size_threshold) { |
| 311 return true; | 308 return true; |
| 312 } | 309 } |
| 313 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { | 310 if (call_site_count <= FLAG_inlining_callee_call_sites_threshold) { |
| 314 return true; | 311 return true; |
| 315 } | 312 } |
| 316 if ((loop_depth > 0) && | |
| 317 (instr_count <= FLAG_inlining_in_loop_size_threshold)) { | |
| 318 return true; | |
| 319 } | |
| 320 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && | 313 if ((const_arg_count >= FLAG_inlining_constant_arguments_count) && |
| 321 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { | 314 (instr_count <= FLAG_inlining_constant_arguments_size_threshold)) { |
| 322 return true; | 315 return true; |
| 323 } | 316 } |
| 324 return false; | 317 return false; |
| 325 } | 318 } |
| 326 | 319 |
| 327 // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently | 320 // TODO(srdjan): Handle large 'skip_static_call_deopt_ids'. Currently |
| 328 // max. size observed is 11 (dart2js). | 321 // max. size observed is 11 (dart2js). |
| 329 void InlineCalls() { | 322 void InlineCalls() { |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 378 } | 371 } |
| 379 | 372 |
| 380 // Abort if this function has deoptimized too much. | 373 // Abort if this function has deoptimized too much. |
| 381 if (function.deoptimization_counter() >= | 374 if (function.deoptimization_counter() >= |
| 382 FLAG_deoptimization_counter_threshold) { | 375 FLAG_deoptimization_counter_threshold) { |
| 383 function.set_is_inlinable(false); | 376 function.set_is_inlinable(false); |
| 384 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 377 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 385 return false; | 378 return false; |
| 386 } | 379 } |
| 387 | 380 |
| 388 const intptr_t loop_depth = call->GetBlock()->loop_depth(); | |
| 389 const intptr_t constant_arguments = CountConstants(*arguments); | 381 const intptr_t constant_arguments = CountConstants(*arguments); |
| 390 if (!ShouldWeInline(loop_depth, | 382 if (!ShouldWeInline(function.optimized_instruction_count(), |
| 391 function.optimized_instruction_count(), | |
| 392 function.optimized_call_site_count(), | 383 function.optimized_call_site_count(), |
| 393 constant_arguments)) { | 384 constant_arguments)) { |
| 394 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 385 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 395 "loop depth: %"Pd", " | |
| 396 "code size: %"Pd", " | 386 "code size: %"Pd", " |
| 397 "call sites: %"Pd", " | 387 "call sites: %"Pd", " |
| 398 "const args: %"Pd"\n", | 388 "const args: %"Pd"\n", |
| 399 loop_depth, | |
| 400 function.optimized_instruction_count(), | 389 function.optimized_instruction_count(), |
| 401 function.optimized_call_site_count(), | 390 function.optimized_call_site_count(), |
| 402 constant_arguments)); | 391 constant_arguments)); |
| 403 return false; | 392 return false; |
| 404 } | 393 } |
| 405 | 394 |
| 406 // Abort if this is a recursive occurrence. | 395 // Abort if this is a recursive occurrence. |
| 407 if (IsCallRecursive(function, call)) { | 396 if (IsCallRecursive(function, call)) { |
| 408 function.set_is_inlinable(false); | 397 function.set_is_inlinable(false); |
| 409 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 398 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 448 | 437 |
| 449 // Build the callee graph. | 438 // Build the callee graph. |
| 450 ValueInliningContext* inlining_context = new ValueInliningContext(); | 439 ValueInliningContext* inlining_context = new ValueInliningContext(); |
| 451 FlowGraphBuilder builder(*parsed_function, inlining_context); | 440 FlowGraphBuilder builder(*parsed_function, inlining_context); |
| 452 builder.SetInitialBlockId(caller_graph_->max_block_id()); | 441 builder.SetInitialBlockId(caller_graph_->max_block_id()); |
| 453 FlowGraph* callee_graph; | 442 FlowGraph* callee_graph; |
| 454 { | 443 { |
| 455 TimerScope timer(FLAG_compiler_stats, | 444 TimerScope timer(FLAG_compiler_stats, |
| 456 &CompilerStats::graphinliner_build_timer, | 445 &CompilerStats::graphinliner_build_timer, |
| 457 isolate); | 446 isolate); |
| 458 callee_graph = builder.BuildGraph(loop_depth); | 447 callee_graph = builder.BuildGraph(); |
| 459 } | 448 } |
| 460 | 449 |
| 461 // The parameter stubs are a copy of the actual arguments providing | 450 // The parameter stubs are a copy of the actual arguments providing |
| 462 // concrete information about the values, for example constant values, | 451 // concrete information about the values, for example constant values, |
| 463 // without linking between the caller and callee graphs. | 452 // without linking between the caller and callee graphs. |
| 464 // TODO(zerny): Put more information in the stubs, eg, type information. | 453 // TODO(zerny): Put more information in the stubs, eg, type information. |
| 465 GrowableArray<Definition*> param_stubs(function.NumParameters()); | 454 GrowableArray<Definition*> param_stubs(function.NumParameters()); |
| 466 | 455 |
| 467 // Create a parameter stub for each fixed positional parameter. | 456 // Create a parameter stub for each fixed positional parameter. |
| 468 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { | 457 for (intptr_t i = 0; i < function.num_fixed_parameters(); ++i) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 530 if (param_stubs[i]->IsConstant()) ++constants_count; | 519 if (param_stubs[i]->IsConstant()) ++constants_count; |
| 531 } | 520 } |
| 532 GraphInfoCollector info; | 521 GraphInfoCollector info; |
| 533 info.Collect(*callee_graph); | 522 info.Collect(*callee_graph); |
| 534 const intptr_t size = info.instruction_count(); | 523 const intptr_t size = info.instruction_count(); |
| 535 | 524 |
| 536 function.set_optimized_instruction_count(size); | 525 function.set_optimized_instruction_count(size); |
| 537 function.set_optimized_call_site_count(info.call_site_count()); | 526 function.set_optimized_call_site_count(info.call_site_count()); |
| 538 | 527 |
| 539 // Use heuristics do decide if this call should be inlined. | 528 // Use heuristics do decide if this call should be inlined. |
| 540 if (!ShouldWeInline(loop_depth, | 529 if (!ShouldWeInline(size, |
| 541 size, | |
| 542 info.call_site_count(), | 530 info.call_site_count(), |
| 543 constants_count)) { | 531 constants_count)) { |
| 544 // If size is larger than all thresholds, don't consider it again. | 532 // If size is larger than all thresholds, don't consider it again. |
| 545 if ((size > FLAG_inlining_size_threshold) && | 533 if ((size > FLAG_inlining_size_threshold) && |
| 546 (size > FLAG_inlining_in_loop_size_threshold) && | |
| 547 (size > FLAG_inlining_callee_call_sites_threshold) && | 534 (size > FLAG_inlining_callee_call_sites_threshold) && |
| 548 (size > FLAG_inlining_constant_arguments_size_threshold)) { | 535 (size > FLAG_inlining_constant_arguments_size_threshold)) { |
| 549 function.set_is_inlinable(false); | 536 function.set_is_inlinable(false); |
| 550 } | 537 } |
| 551 isolate->set_long_jump_base(base); | 538 isolate->set_long_jump_base(base); |
| 552 isolate->set_deopt_id(prev_deopt_id); | 539 isolate->set_deopt_id(prev_deopt_id); |
| 553 isolate->set_ic_data_array(prev_ic_data.raw()); | 540 isolate->set_ic_data_array(prev_ic_data.raw()); |
| 554 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 541 TRACE_INLINING(OS::Print(" Bailout: heuristics with " |
| 555 "loop depth: %"Pd", " | |
| 556 "code size: %"Pd", " | 542 "code size: %"Pd", " |
| 557 "call sites: %"Pd", " | 543 "call sites: %"Pd", " |
| 558 "const args: %"Pd"\n", | 544 "const args: %"Pd"\n", |
| 559 loop_depth, | |
| 560 size, | 545 size, |
| 561 info.call_site_count(), | 546 info.call_site_count(), |
| 562 constants_count)); | 547 constants_count)); |
| 563 return false; | 548 return false; |
| 564 } | 549 } |
| 565 | 550 |
| 566 // If depth is less or equal to threshold recursively add call sites. | 551 // If depth is less or equal to threshold recursively add call sites. |
| 567 if (inlining_depth_ < FLAG_inlining_depth_threshold) { | 552 if (inlining_depth_ < FLAG_inlining_depth_threshold) { |
| 568 collected_call_sites_->FindCallSites(callee_graph); | 553 collected_call_sites_->FindCallSites(callee_graph); |
| 569 } | 554 } |
| (...skipping 313 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 OS::Print("After Inlining of %s\n", flow_graph_-> | 868 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 884 parsed_function().function().ToFullyQualifiedCString()); | 869 parsed_function().function().ToFullyQualifiedCString()); |
| 885 FlowGraphPrinter printer(*flow_graph_); | 870 FlowGraphPrinter printer(*flow_graph_); |
| 886 printer.PrintBlocks(); | 871 printer.PrintBlocks(); |
| 887 } | 872 } |
| 888 } | 873 } |
| 889 } | 874 } |
| 890 } | 875 } |
| 891 | 876 |
| 892 } // namespace dart | 877 } // namespace dart |
| OLD | NEW |