| 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 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 55 DECLARE_FLAG(bool, print_flow_graph_optimized); | 55 DECLARE_FLAG(bool, print_flow_graph_optimized); |
| 56 DECLARE_FLAG(int, deoptimization_counter_threshold); | 56 DECLARE_FLAG(int, deoptimization_counter_threshold); |
| 57 DECLARE_FLAG(bool, verify_compiler); | 57 DECLARE_FLAG(bool, verify_compiler); |
| 58 DECLARE_FLAG(bool, compiler_stats); | 58 DECLARE_FLAG(bool, compiler_stats); |
| 59 | 59 |
| 60 #define TRACE_INLINING(statement) \ | 60 #define TRACE_INLINING(statement) \ |
| 61 do { \ | 61 do { \ |
| 62 if (FLAG_trace_inlining) statement; \ | 62 if (FLAG_trace_inlining) statement; \ |
| 63 } while (false) | 63 } while (false) |
| 64 | 64 |
| 65 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ |
| 66 do { \ |
| 67 if (FLAG_print_inlining_tree) { \ |
| 68 inlined_info_.Add(InlinedInfo( \ |
| 69 caller, target, inlining_depth_, instance_call, comment)); \ |
| 70 } \ |
| 71 } while (false) \ |
| 72 |
| 65 | 73 |
| 66 // Test if a call is recursive by looking in the deoptimization environment. | 74 // Test if a call is recursive by looking in the deoptimization environment. |
| 67 static bool IsCallRecursive(const Code& code, Definition* call) { | 75 static bool IsCallRecursive(const Code& code, Definition* call) { |
| 68 Environment* env = call->env(); | 76 Environment* env = call->env(); |
| 69 while (env != NULL) { | 77 while (env != NULL) { |
| 70 if (code.raw() == env->code().raw()) { | 78 if (code.raw() == env->code().raw()) { |
| 71 return true; | 79 return true; |
| 72 } | 80 } |
| 73 env = env->outer(); | 81 env = env->outer(); |
| 74 } | 82 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 160 struct InlinedInfo { | 168 struct InlinedInfo { |
| 161 const Function* caller; | 169 const Function* caller; |
| 162 const Function* inlined; | 170 const Function* inlined; |
| 163 intptr_t inlined_depth; | 171 intptr_t inlined_depth; |
| 164 const Definition* call_instr; | 172 const Definition* call_instr; |
| 165 const char* bailout_reason; | 173 const char* bailout_reason; |
| 166 InlinedInfo(const Function* caller_function, | 174 InlinedInfo(const Function* caller_function, |
| 167 const Function* inlined_function, | 175 const Function* inlined_function, |
| 168 const intptr_t depth, | 176 const intptr_t depth, |
| 169 const Definition* call, | 177 const Definition* call, |
| 170 const char* reason = NULL) | 178 const char* reason) |
| 171 : caller(caller_function), | 179 : caller(caller_function), |
| 172 inlined(inlined_function), | 180 inlined(inlined_function), |
| 173 inlined_depth(depth), | 181 inlined_depth(depth), |
| 174 call_instr(call), | 182 call_instr(call), |
| 175 bailout_reason(reason) {} | 183 bailout_reason(reason) {} |
| 176 }; | 184 }; |
| 177 | 185 |
| 178 | 186 |
| 179 // A collection of call sites to consider for inlining. | 187 // A collection of call sites to consider for inlining. |
| 180 class CallSites : public ValueObject { | 188 class CallSites : public ValueObject { |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 269 0.0 : static_cast<double>(instance_call_counts[i]) / max_count; | 277 0.0 : static_cast<double>(instance_call_counts[i]) / max_count; |
| 270 instance_calls_[i + instance_call_start_ix].ratio = ratio; | 278 instance_calls_[i + instance_call_start_ix].ratio = ratio; |
| 271 } | 279 } |
| 272 for (intptr_t i = 0; i < num_static_calls; ++i) { | 280 for (intptr_t i = 0; i < num_static_calls; ++i) { |
| 273 const double ratio = (max_count == 0) ? | 281 const double ratio = (max_count == 0) ? |
| 274 0.0 : static_cast<double>(static_call_counts[i]) / max_count; | 282 0.0 : static_cast<double>(static_call_counts[i]) / max_count; |
| 275 static_calls_[i + static_call_start_ix].ratio = ratio; | 283 static_calls_[i + static_call_start_ix].ratio = ratio; |
| 276 } | 284 } |
| 277 } | 285 } |
| 278 | 286 |
| 287 static void RecordAllNotInlinedFunction( |
| 288 FlowGraph* graph, |
| 289 intptr_t depth, |
| 290 GrowableArray<InlinedInfo>* inlined_info) { |
| 291 const Function* caller = &graph->parsed_function().function(); |
| 292 Function& target = Function::ZoneHandle(); |
| 293 for (BlockIterator block_it = graph->postorder_iterator(); |
| 294 !block_it.Done(); |
| 295 block_it.Advance()) { |
| 296 for (ForwardInstructionIterator it(block_it.Current()); |
| 297 !it.Done(); |
| 298 it.Advance()) { |
| 299 Instruction* current = it.Current(); |
| 300 Definition* call = NULL; |
| 301 if (current->IsPolymorphicInstanceCall()) { |
| 302 PolymorphicInstanceCallInstr* instance_call = |
| 303 current->AsPolymorphicInstanceCall(); |
| 304 target = instance_call->ic_data().GetTargetAt(0); |
| 305 call = instance_call; |
| 306 } else if (current->IsStaticCall()) { |
| 307 StaticCallInstr* static_call = current->AsStaticCall(); |
| 308 target = static_call->function().raw(); |
| 309 call = static_call; |
| 310 } else if (current->IsClosureCall()) { |
| 311 // TODO(srdjan): Add data for closure calls. |
| 312 } |
| 313 if (call != NULL) { |
| 314 inlined_info->Add(InlinedInfo( |
| 315 caller, &target, depth + 1, call, "Too deep")); |
| 316 } |
| 317 } |
| 318 } |
| 319 } |
| 320 |
| 321 |
| 279 void FindCallSites(FlowGraph* graph, | 322 void FindCallSites(FlowGraph* graph, |
| 280 intptr_t depth, | 323 intptr_t depth, |
| 281 GrowableArray<InlinedInfo>* inlined_info) { | 324 GrowableArray<InlinedInfo>* inlined_info) { |
| 282 ASSERT(graph != NULL); | 325 ASSERT(graph != NULL); |
| 283 | 326 if (depth > FLAG_inlining_depth_threshold) { |
| 284 if (depth > FLAG_inlining_depth_threshold) return; | 327 if (FLAG_print_inlining_tree) { |
| 328 RecordAllNotInlinedFunction(graph, depth, inlined_info); |
| 329 } |
| 330 return; |
| 331 } |
| 285 | 332 |
| 286 // Recognized methods are not treated as normal calls. They don't have | 333 // Recognized methods are not treated as normal calls. They don't have |
| 287 // calls in themselves, so we keep adding those even when at the threshold. | 334 // calls in themselves, so we keep adding those even when at the threshold. |
| 288 const bool inline_only_recognized_methods = | 335 const bool inline_only_recognized_methods = |
| 289 (depth == FLAG_inlining_depth_threshold); | 336 (depth == FLAG_inlining_depth_threshold); |
| 290 | 337 |
| 291 const intptr_t instance_call_start_ix = instance_calls_.length(); | 338 const intptr_t instance_call_start_ix = instance_calls_.length(); |
| 292 const intptr_t static_call_start_ix = static_calls_.length(); | 339 const intptr_t static_call_start_ix = static_calls_.length(); |
| 293 for (BlockIterator block_it = graph->postorder_iterator(); | 340 for (BlockIterator block_it = graph->postorder_iterator(); |
| 294 !block_it.Done(); | 341 !block_it.Done(); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 306 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); | 353 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); |
| 307 } else { | 354 } else { |
| 308 // Method not inlined because inlining too deep and method | 355 // Method not inlined because inlining too deep and method |
| 309 // not recognized. | 356 // not recognized. |
| 310 if (FLAG_print_inlining_tree) { | 357 if (FLAG_print_inlining_tree) { |
| 311 const Function* caller = &graph->parsed_function().function(); | 358 const Function* caller = &graph->parsed_function().function(); |
| 312 const Function* target = | 359 const Function* target = |
| 313 &Function::ZoneHandle( | 360 &Function::ZoneHandle( |
| 314 instance_call->ic_data().GetTargetAt(0)); | 361 instance_call->ic_data().GetTargetAt(0)); |
| 315 inlined_info->Add(InlinedInfo( | 362 inlined_info->Add(InlinedInfo( |
| 316 caller, target, depth, instance_call, "Too deep")); | 363 caller, target, depth + 1, instance_call, "Too deep")); |
| 317 } | 364 } |
| 318 } | 365 } |
| 319 } else if (current->IsStaticCall()) { | 366 } else if (current->IsStaticCall()) { |
| 320 StaticCallInstr* static_call = current->AsStaticCall(); | 367 StaticCallInstr* static_call = current->AsStaticCall(); |
| 321 if (!inline_only_recognized_methods || | 368 if (!inline_only_recognized_methods || |
| 322 static_call->function().is_recognized()) { | 369 static_call->function().is_recognized()) { |
| 323 static_calls_.Add(StaticCallInfo(static_call, graph)); | 370 static_calls_.Add(StaticCallInfo(static_call, graph)); |
| 324 } else { | 371 } else { |
| 325 // Method not inlined because inlining too deep and method | 372 // Method not inlined because inlining too deep and method |
| 326 // not recognized. | 373 // not recognized. |
| 327 if (FLAG_print_inlining_tree) { | 374 if (FLAG_print_inlining_tree) { |
| 328 const Function* caller = &graph->parsed_function().function(); | 375 const Function* caller = &graph->parsed_function().function(); |
| 329 const Function* target = &static_call->function(); | 376 const Function* target = &static_call->function(); |
| 330 inlined_info->Add(InlinedInfo( | 377 inlined_info->Add(InlinedInfo( |
| 331 caller, target, depth, static_call, "Too deep")); | 378 caller, target, depth + 1, static_call, "Too deep")); |
| 332 } | 379 } |
| 333 } | 380 } |
| 334 } else if (current->IsClosureCall()) { | 381 } else if (current->IsClosureCall()) { |
| 335 if (!inline_only_recognized_methods) { | 382 if (!inline_only_recognized_methods) { |
| 336 ClosureCallInstr* closure_call = current->AsClosureCall(); | 383 ClosureCallInstr* closure_call = current->AsClosureCall(); |
| 337 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); | 384 closure_calls_.Add(ClosureCallInfo(closure_call, graph)); |
| 338 } | 385 } |
| 339 } | 386 } |
| 340 } | 387 } |
| 341 } | 388 } |
| (...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 495 const Array& argument_names, | 542 const Array& argument_names, |
| 496 InlinedCallData* call_data) { | 543 InlinedCallData* call_data) { |
| 497 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", | 544 TRACE_INLINING(OS::Print(" => %s (deopt count %d)\n", |
| 498 function.ToCString(), | 545 function.ToCString(), |
| 499 function.deoptimization_counter())); | 546 function.deoptimization_counter())); |
| 500 | 547 |
| 501 // TODO(fschneider): Enable inlining inside try-blocks. | 548 // TODO(fschneider): Enable inlining inside try-blocks. |
| 502 if (call_data->call->GetBlock()->try_index() != | 549 if (call_data->call->GetBlock()->try_index() != |
| 503 CatchClauseNode::kInvalidTryIndex) { | 550 CatchClauseNode::kInvalidTryIndex) { |
| 504 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n")); | 551 TRACE_INLINING(OS::Print(" Bailout: inside try-block\n")); |
| 505 if (FLAG_print_inlining_tree) { | 552 PRINT_INLINING_TREE("Inside try-block", |
| 506 inlined_info_.Add(InlinedInfo( | 553 &call_data->caller, &function, call_data->call); |
| 507 &call_data->caller, &function, inlining_depth_, call_data->call, | |
| 508 "Inside try-block")); | |
| 509 } | |
| 510 return false; | 554 return false; |
| 511 } | 555 } |
| 512 | 556 |
| 513 // Make a handle for the unoptimized code so that it is not disconnected | 557 // Make a handle for the unoptimized code so that it is not disconnected |
| 514 // from the function while we are trying to inline it. | 558 // from the function while we are trying to inline it. |
| 515 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); | 559 const Code& unoptimized_code = Code::Handle(function.unoptimized_code()); |
| 516 // Abort if the inlinable bit on the function is low. | 560 // Abort if the inlinable bit on the function is low. |
| 517 if (!function.IsInlineable()) { | 561 if (!function.IsInlineable()) { |
| 518 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); | 562 TRACE_INLINING(OS::Print(" Bailout: not inlinable\n")); |
| 519 if (FLAG_print_inlining_tree) { | 563 PRINT_INLINING_TREE("Not inlinable", |
| 520 inlined_info_.Add(InlinedInfo( | 564 &call_data->caller, &function, call_data->call); |
| 521 &call_data->caller, &function, inlining_depth_, call_data->call, | |
| 522 "Not inlinable")); | |
| 523 } | |
| 524 return false; | 565 return false; |
| 525 } | 566 } |
| 526 | 567 |
| 527 // Abort if this function has deoptimized too much. | 568 // Abort if this function has deoptimized too much. |
| 528 if (function.deoptimization_counter() >= | 569 if (function.deoptimization_counter() >= |
| 529 FLAG_deoptimization_counter_threshold) { | 570 FLAG_deoptimization_counter_threshold) { |
| 530 function.set_is_inlinable(false); | 571 function.set_is_inlinable(false); |
| 531 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); | 572 TRACE_INLINING(OS::Print(" Bailout: deoptimization threshold\n")); |
| 532 if (FLAG_print_inlining_tree) { | 573 PRINT_INLINING_TREE("Deoptimization threshold exceeded", |
| 533 inlined_info_.Add(InlinedInfo( | 574 &call_data->caller, &function, call_data->call); |
| 534 &call_data->caller, &function, inlining_depth_, call_data->call, | |
| 535 "Deoptimization threshold exceeded")); | |
| 536 } | |
| 537 return false; | 575 return false; |
| 538 } | 576 } |
| 539 | 577 |
| 540 GrowableArray<Value*>* arguments = call_data->arguments; | 578 GrowableArray<Value*>* arguments = call_data->arguments; |
| 541 const intptr_t constant_arguments = CountConstants(*arguments); | 579 const intptr_t constant_arguments = CountConstants(*arguments); |
| 542 if (!ShouldWeInline(function, | 580 if (!ShouldWeInline(function, |
| 543 function.optimized_instruction_count(), | 581 function.optimized_instruction_count(), |
| 544 function.optimized_call_site_count(), | 582 function.optimized_call_site_count(), |
| 545 constant_arguments)) { | 583 constant_arguments)) { |
| 546 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " | 584 TRACE_INLINING(OS::Print(" Bailout: early heuristics with " |
| 547 "code size: %" Pd ", " | 585 "code size: %" Pd ", " |
| 548 "call sites: %" Pd ", " | 586 "call sites: %" Pd ", " |
| 549 "const args: %" Pd "\n", | 587 "const args: %" Pd "\n", |
| 550 function.optimized_instruction_count(), | 588 function.optimized_instruction_count(), |
| 551 function.optimized_call_site_count(), | 589 function.optimized_call_site_count(), |
| 552 constant_arguments)); | 590 constant_arguments)); |
| 553 if (FLAG_print_inlining_tree) { | 591 PRINT_INLINING_TREE("Early heuristic", |
| 554 inlined_info_.Add(InlinedInfo( | 592 &call_data->caller, &function, call_data->call); |
| 555 &call_data->caller, &function, inlining_depth_, call_data->call, | |
| 556 "Early heuristic")); | |
| 557 } | |
| 558 return false; | 593 return false; |
| 559 } | 594 } |
| 560 | 595 |
| 561 // Abort if this is a recursive occurrence. | 596 // Abort if this is a recursive occurrence. |
| 562 Definition* call = call_data->call; | 597 Definition* call = call_data->call; |
| 563 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { | 598 if (!FLAG_inline_recursive && IsCallRecursive(unoptimized_code, call)) { |
| 564 function.set_is_inlinable(false); | 599 function.set_is_inlinable(false); |
| 565 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); | 600 TRACE_INLINING(OS::Print(" Bailout: recursive function\n")); |
| 601 PRINT_INLINING_TREE("Recursive function", |
| 602 &call_data->caller, &function, call_data->call); |
| 566 return false; | 603 return false; |
| 567 } | 604 } |
| 568 | 605 |
| 569 Isolate* isolate = Isolate::Current(); | 606 Isolate* isolate = Isolate::Current(); |
| 570 // Save and clear deopt id. | 607 // Save and clear deopt id. |
| 571 const intptr_t prev_deopt_id = isolate->deopt_id(); | 608 const intptr_t prev_deopt_id = isolate->deopt_id(); |
| 572 isolate->set_deopt_id(0); | 609 isolate->set_deopt_id(0); |
| 573 // Install bailout jump. | 610 // Install bailout jump. |
| 574 LongJumpScope jump; | 611 LongJumpScope jump; |
| 575 if (setjmp(*jump.Set()) == 0) { | 612 if (setjmp(*jump.Set()) == 0) { |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 625 // parameters. | 662 // parameters. |
| 626 if (function.HasOptionalParameters()) { | 663 if (function.HasOptionalParameters()) { |
| 627 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); | 664 TRACE_INLINING(OS::Print(" adjusting for optional parameters\n")); |
| 628 if (!AdjustForOptionalParameters(*parsed_function, | 665 if (!AdjustForOptionalParameters(*parsed_function, |
| 629 argument_names, | 666 argument_names, |
| 630 arguments, | 667 arguments, |
| 631 param_stubs, | 668 param_stubs, |
| 632 callee_graph)) { | 669 callee_graph)) { |
| 633 function.set_is_inlinable(false); | 670 function.set_is_inlinable(false); |
| 634 TRACE_INLINING(OS::Print(" Bailout: optional arg mismatch\n")); | 671 TRACE_INLINING(OS::Print(" Bailout: optional arg mismatch\n")); |
| 672 PRINT_INLINING_TREE("Optional arg mismatch", |
| 673 &call_data->caller, &function, call_data->call); |
| 635 return false; | 674 return false; |
| 636 } | 675 } |
| 637 } | 676 } |
| 638 | 677 |
| 639 // After treating optional parameters the actual/formal count must match. | 678 // After treating optional parameters the actual/formal count must match. |
| 640 ASSERT(arguments->length() == function.NumParameters()); | 679 ASSERT(arguments->length() == function.NumParameters()); |
| 641 ASSERT(param_stubs->length() == callee_graph->parameter_count()); | 680 ASSERT(param_stubs->length() == callee_graph->parameter_count()); |
| 642 | 681 |
| 643 BlockScheduler block_scheduler(callee_graph); | 682 BlockScheduler block_scheduler(callee_graph); |
| 644 block_scheduler.AssignEdgeWeights(); | 683 block_scheduler.AssignEdgeWeights(); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 699 function.set_is_inlinable(false); | 738 function.set_is_inlinable(false); |
| 700 } | 739 } |
| 701 isolate->set_deopt_id(prev_deopt_id); | 740 isolate->set_deopt_id(prev_deopt_id); |
| 702 TRACE_INLINING(OS::Print(" Bailout: heuristics with " | 741 TRACE_INLINING(OS::Print(" Bailout: heuristics with " |
| 703 "code size: %" Pd ", " | 742 "code size: %" Pd ", " |
| 704 "call sites: %" Pd ", " | 743 "call sites: %" Pd ", " |
| 705 "const args: %" Pd "\n", | 744 "const args: %" Pd "\n", |
| 706 size, | 745 size, |
| 707 call_site_count, | 746 call_site_count, |
| 708 constants_count)); | 747 constants_count)); |
| 709 if (FLAG_print_inlining_tree) { | 748 PRINT_INLINING_TREE("Heuristic fail", |
| 710 inlined_info_.Add(InlinedInfo( | 749 &call_data->caller, &function, call_data->call); |
| 711 &call_data->caller, &function, inlining_depth_, call_data->call, | |
| 712 "Heuristic fail")); | |
| 713 } | |
| 714 return false; | 750 return false; |
| 715 } | 751 } |
| 716 | 752 |
| 717 if (function.IsInvokeFieldDispatcher() || | 753 if (function.IsInvokeFieldDispatcher() || |
| 718 function.IsNoSuchMethodDispatcher()) { | 754 function.IsNoSuchMethodDispatcher()) { |
| 719 // Append call sites to the currently processed list so that dispatcher | 755 // Append call sites to the currently processed list so that dispatcher |
| 720 // methods get inlined regardless of the current depth. | 756 // methods get inlined regardless of the current depth. |
| 721 inlining_call_sites_->FindCallSites(callee_graph, | 757 inlining_call_sites_->FindCallSites(callee_graph, |
| 722 0, | 758 0, |
| 723 &inlined_info_); | 759 &inlined_info_); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 745 // list of guarded fields. | 781 // list of guarded fields. |
| 746 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { | 782 for (intptr_t i = 0; i < callee_graph->guarded_fields()->length(); ++i) { |
| 747 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), | 783 FlowGraph::AddToGuardedFields(caller_graph_->guarded_fields(), |
| 748 (*callee_graph->guarded_fields())[i]); | 784 (*callee_graph->guarded_fields())[i]); |
| 749 } | 785 } |
| 750 | 786 |
| 751 // We allocate a ZoneHandle for the unoptimized code so that it cannot be | 787 // We allocate a ZoneHandle for the unoptimized code so that it cannot be |
| 752 // disconnected from its function during the rest of compilation. | 788 // disconnected from its function during the rest of compilation. |
| 753 Code::ZoneHandle(unoptimized_code.raw()); | 789 Code::ZoneHandle(unoptimized_code.raw()); |
| 754 TRACE_INLINING(OS::Print(" Success\n")); | 790 TRACE_INLINING(OS::Print(" Success\n")); |
| 755 if (FLAG_print_inlining_tree) { | 791 PRINT_INLINING_TREE(NULL, |
| 756 inlined_info_.Add( | 792 &call_data->caller, &function, call); |
| 757 InlinedInfo(&call_data->caller, &function, inlining_depth_, call)); | |
| 758 } | |
| 759 return true; | 793 return true; |
| 760 } else { | 794 } else { |
| 761 Error& error = Error::Handle(); | 795 Error& error = Error::Handle(); |
| 762 error = isolate->object_store()->sticky_error(); | 796 error = isolate->object_store()->sticky_error(); |
| 763 isolate->object_store()->clear_sticky_error(); | 797 isolate->object_store()->clear_sticky_error(); |
| 764 isolate->set_deopt_id(prev_deopt_id); | 798 isolate->set_deopt_id(prev_deopt_id); |
| 765 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); | 799 TRACE_INLINING(OS::Print(" Bailout: %s\n", error.ToErrorCString())); |
| 800 PRINT_INLINING_TREE("Bailout", |
| 801 &call_data->caller, &function, call); |
| 766 return false; | 802 return false; |
| 767 } | 803 } |
| 768 } | 804 } |
| 769 | 805 |
| 770 void PrintInlinedInfo(const Function& top) { | 806 void PrintInlinedInfo(const Function& top) { |
| 771 if (inlined_info_.length() > 0) { | 807 if (inlined_info_.length() > 0) { |
| 772 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", | 808 OS::Print("Inlining into: '%s' growth: %f (%" Pd " -> %" Pd ")\n", |
| 773 top.ToFullyQualifiedCString(), | 809 top.ToFullyQualifiedCString(), |
| 774 GrowthFactor(), | 810 GrowthFactor(), |
| 775 initial_size_, | 811 initial_size_, |
| 776 inlined_size_); | 812 inlined_size_); |
| 777 PrintInlinedInfoFor(top, 1); | 813 PrintInlinedInfoFor(top, 1); |
| 778 } | 814 } |
| 779 } | 815 } |
| 780 | 816 |
| 781 private: | 817 private: |
| 782 friend class PolymorphicInliner; | 818 friend class PolymorphicInliner; |
| 783 | 819 |
| 784 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) { | 820 void PrintInlinedInfoFor(const Function& caller, intptr_t depth) { |
| 785 // Print those that were inlined. | 821 // Print those that were inlined. |
| 786 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 822 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
| 787 const InlinedInfo& info = inlined_info_[i]; | 823 const InlinedInfo& info = inlined_info_[i]; |
| 788 if (info.bailout_reason != NULL) continue; | 824 if (info.bailout_reason != NULL) { |
| 825 continue; |
| 826 } |
| 789 if ((info.inlined_depth == depth) && | 827 if ((info.inlined_depth == depth) && |
| 790 (info.caller->raw() == caller.raw())) { | 828 (info.caller->raw() == caller.raw())) { |
| 791 for (int t = 0; t < depth; t++) { | 829 for (int t = 0; t < depth; t++) { |
| 792 OS::Print(" "); | 830 OS::Print(" "); |
| 793 } | 831 } |
| 794 OS::Print("%" Pd " %s\n", | 832 OS::Print("%" Pd " %s\n", |
| 795 info.call_instr->GetDeoptId(), | 833 info.call_instr->GetDeoptId(), |
| 796 info.inlined->ToQualifiedCString()); | 834 info.inlined->ToQualifiedCString()); |
| 797 PrintInlinedInfoFor(*info.inlined, depth + 1); | 835 PrintInlinedInfoFor(*info.inlined, depth + 1); |
| 798 } | 836 } |
| 799 } | 837 } |
| 800 // Print those that were not inlined. | 838 // Print those that were not inlined. |
| 801 for (intptr_t i = 0; i < inlined_info_.length(); i++) { | 839 for (intptr_t i = 0; i < inlined_info_.length(); i++) { |
| 802 const InlinedInfo& info = inlined_info_[i]; | 840 const InlinedInfo& info = inlined_info_[i]; |
| 803 if (info.bailout_reason == NULL) continue; | 841 if (info.bailout_reason == NULL) { |
| 842 continue; |
| 843 } |
| 804 if ((info.inlined_depth == depth) && | 844 if ((info.inlined_depth == depth) && |
| 805 (info.caller->raw() == caller.raw())) { | 845 (info.caller->raw() == caller.raw())) { |
| 806 for (int t = 0; t < depth; t++) { | 846 for (int t = 0; t < depth; t++) { |
| 807 OS::Print(" "); | 847 OS::Print(" "); |
| 808 } | 848 } |
| 809 OS::Print("NO %" Pd " %s - %s\n", | 849 OS::Print("NO %" Pd " %s - %s\n", |
| 810 info.call_instr->GetDeoptId(), | 850 info.call_instr->GetDeoptId(), |
| 811 info.inlined->ToQualifiedCString(), | 851 info.inlined->ToQualifiedCString(), |
| 812 info.bailout_reason); | 852 info.bailout_reason); |
| 813 } | 853 } |
| (...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 923 } | 963 } |
| 924 } | 964 } |
| 925 const Function& target = call->function(); | 965 const Function& target = call->function(); |
| 926 if (!FlowGraphInliner::AlwaysInline(target) && | 966 if (!FlowGraphInliner::AlwaysInline(target) && |
| 927 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 967 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 928 TRACE_INLINING(OS::Print( | 968 TRACE_INLINING(OS::Print( |
| 929 " => %s (deopt count %d)\n Bailout: cold %f\n", | 969 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 930 target.ToCString(), | 970 target.ToCString(), |
| 931 target.deoptimization_counter(), | 971 target.deoptimization_counter(), |
| 932 call_info[call_idx].ratio)); | 972 call_info[call_idx].ratio)); |
| 933 if (FLAG_print_inlining_tree) { | 973 PRINT_INLINING_TREE("Too cold", |
| 934 inlined_info_.Add(InlinedInfo( | 974 call_info[call_idx].caller, &call->function(), call); |
| 935 call_info[call_idx].caller, | |
| 936 &call->function(), | |
| 937 inlining_depth_, | |
| 938 call, | |
| 939 "Too cold")); | |
| 940 } | |
| 941 continue; | 975 continue; |
| 942 } | 976 } |
| 943 GrowableArray<Value*> arguments(call->ArgumentCount()); | 977 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 944 for (int i = 0; i < call->ArgumentCount(); ++i) { | 978 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 945 arguments.Add(call->PushArgumentAt(i)->value()); | 979 arguments.Add(call->PushArgumentAt(i)->value()); |
| 946 } | 980 } |
| 947 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); | 981 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); |
| 948 if (TryInlining(call->function(), call->argument_names(), &call_data)) { | 982 if (TryInlining(call->function(), call->argument_names(), &call_data)) { |
| 949 InlineCall(&call_data); | 983 InlineCall(&call_data); |
| 950 } | 984 } |
| (...skipping 11 matching lines...) Expand all Loading... |
| 962 ASSERT(call->ArgumentCount() > 0); | 996 ASSERT(call->ArgumentCount() > 0); |
| 963 Function& target = Function::ZoneHandle(); | 997 Function& target = Function::ZoneHandle(); |
| 964 AllocateObjectInstr* alloc = | 998 AllocateObjectInstr* alloc = |
| 965 call->ArgumentAt(0)->AsAllocateObject(); | 999 call->ArgumentAt(0)->AsAllocateObject(); |
| 966 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { | 1000 if ((alloc != NULL) && !alloc->closure_function().IsNull()) { |
| 967 target ^= alloc->closure_function().raw(); | 1001 target ^= alloc->closure_function().raw(); |
| 968 ASSERT(target.signature_class() == alloc->cls().raw()); | 1002 ASSERT(target.signature_class() == alloc->cls().raw()); |
| 969 } | 1003 } |
| 970 if (target.IsNull()) { | 1004 if (target.IsNull()) { |
| 971 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); | 1005 TRACE_INLINING(OS::Print(" Bailout: non-closure operator\n")); |
| 1006 PRINT_INLINING_TREE("Non-closure operator", |
| 1007 call_info[call_idx].caller, &target, call); |
| 972 continue; | 1008 continue; |
| 973 } | 1009 } |
| 974 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1010 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 975 for (int i = 0; i < call->ArgumentCount(); ++i) { | 1011 for (int i = 0; i < call->ArgumentCount(); ++i) { |
| 976 arguments.Add(call->PushArgumentAt(i)->value()); | 1012 arguments.Add(call->PushArgumentAt(i)->value()); |
| 977 } | 1013 } |
| 978 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); | 1014 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); |
| 979 if (TryInlining(target, | 1015 if (TryInlining(target, |
| 980 call->argument_names(), | 1016 call->argument_names(), |
| 981 &call_data)) { | 1017 &call_data)) { |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1000 | 1036 |
| 1001 const ICData& ic_data = call->ic_data(); | 1037 const ICData& ic_data = call->ic_data(); |
| 1002 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | 1038 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); |
| 1003 if (!FlowGraphInliner::AlwaysInline(target) && | 1039 if (!FlowGraphInliner::AlwaysInline(target) && |
| 1004 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1040 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
| 1005 TRACE_INLINING(OS::Print( | 1041 TRACE_INLINING(OS::Print( |
| 1006 " => %s (deopt count %d)\n Bailout: cold %f\n", | 1042 " => %s (deopt count %d)\n Bailout: cold %f\n", |
| 1007 target.ToCString(), | 1043 target.ToCString(), |
| 1008 target.deoptimization_counter(), | 1044 target.deoptimization_counter(), |
| 1009 call_info[call_idx].ratio)); | 1045 call_info[call_idx].ratio)); |
| 1010 if (FLAG_print_inlining_tree) { | 1046 PRINT_INLINING_TREE("Too cold", |
| 1011 inlined_info_.Add(InlinedInfo( | 1047 call_info[call_idx].caller, &target, call); |
| 1012 call_info[call_idx].caller, | |
| 1013 &target, | |
| 1014 inlining_depth_, | |
| 1015 call, | |
| 1016 "Too cold")); | |
| 1017 } | |
| 1018 continue; | 1048 continue; |
| 1019 } | 1049 } |
| 1020 GrowableArray<Value*> arguments(call->ArgumentCount()); | 1050 GrowableArray<Value*> arguments(call->ArgumentCount()); |
| 1021 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { | 1051 for (int arg_i = 0; arg_i < call->ArgumentCount(); ++arg_i) { |
| 1022 arguments.Add(call->PushArgumentAt(arg_i)->value()); | 1052 arguments.Add(call->PushArgumentAt(arg_i)->value()); |
| 1023 } | 1053 } |
| 1024 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); | 1054 InlinedCallData call_data(call, &arguments, *call_info[call_idx].caller); |
| 1025 if (TryInlining(target, | 1055 if (TryInlining(target, |
| 1026 call->instance_call()->argument_names(), | 1056 call->instance_call()->argument_names(), |
| 1027 &call_data)) { | 1057 &call_data)) { |
| (...skipping 631 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1659 OS::Print("After Inlining of %s\n", flow_graph_-> | 1689 OS::Print("After Inlining of %s\n", flow_graph_-> |
| 1660 parsed_function().function().ToFullyQualifiedCString()); | 1690 parsed_function().function().ToFullyQualifiedCString()); |
| 1661 FlowGraphPrinter printer(*flow_graph_); | 1691 FlowGraphPrinter printer(*flow_graph_); |
| 1662 printer.PrintBlocks(); | 1692 printer.PrintBlocks(); |
| 1663 } | 1693 } |
| 1664 } | 1694 } |
| 1665 } | 1695 } |
| 1666 } | 1696 } |
| 1667 | 1697 |
| 1668 } // namespace dart | 1698 } // namespace dart |
| OLD | NEW |