| 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 #if !defined(DART_PRECOMPILED_RUNTIME) | 4 #if !defined(DART_PRECOMPILED_RUNTIME) |
| 5 #include "vm/flow_graph_inliner.h" | 5 #include "vm/flow_graph_inliner.h" |
| 6 | 6 |
| 7 #include "vm/aot_optimizer.h" | 7 #include "vm/aot_optimizer.h" |
| 8 #include "vm/precompiler.h" | |
| 9 #include "vm/block_scheduler.h" | 8 #include "vm/block_scheduler.h" |
| 10 #include "vm/branch_optimizer.h" | 9 #include "vm/branch_optimizer.h" |
| 11 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| 12 #include "vm/kernel.h" | |
| 13 #include "vm/kernel_to_il.h" | |
| 14 #include "vm/flags.h" | 11 #include "vm/flags.h" |
| 15 #include "vm/flow_graph.h" | 12 #include "vm/flow_graph.h" |
| 16 #include "vm/flow_graph_builder.h" | 13 #include "vm/flow_graph_builder.h" |
| 17 #include "vm/flow_graph_compiler.h" | 14 #include "vm/flow_graph_compiler.h" |
| 18 #include "vm/flow_graph_type_propagator.h" | 15 #include "vm/flow_graph_type_propagator.h" |
| 19 #include "vm/il_printer.h" | 16 #include "vm/il_printer.h" |
| 20 #include "vm/jit_optimizer.h" | 17 #include "vm/jit_optimizer.h" |
| 18 #include "vm/kernel.h" |
| 19 #include "vm/kernel_to_il.h" |
| 21 #include "vm/longjump.h" | 20 #include "vm/longjump.h" |
| 22 #include "vm/object.h" | 21 #include "vm/object.h" |
| 23 #include "vm/object_store.h" | 22 #include "vm/object_store.h" |
| 23 #include "vm/precompiler.h" |
| 24 #include "vm/timer.h" | 24 #include "vm/timer.h" |
| 25 | 25 |
| 26 namespace dart { | 26 namespace dart { |
| 27 | 27 |
| 28 DEFINE_FLAG(int, | 28 DEFINE_FLAG(int, |
| 29 deoptimization_counter_inlining_threshold, | 29 deoptimization_counter_inlining_threshold, |
| 30 12, | 30 12, |
| 31 "How many times we allow deoptimization before we stop inlining."); | 31 "How many times we allow deoptimization before we stop inlining."); |
| 32 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); | 32 DEFINE_FLAG(bool, trace_inlining, false, "Trace inlining"); |
| 33 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); | 33 DEFINE_FLAG(charp, inlining_filter, NULL, "Inline only in named function"); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 } while (false) | 109 } while (false) |
| 110 | 110 |
| 111 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ | 111 #define PRINT_INLINING_TREE(comment, caller, target, instance_call) \ |
| 112 do { \ | 112 do { \ |
| 113 if (FLAG_print_inlining_tree) { \ | 113 if (FLAG_print_inlining_tree) { \ |
| 114 inlined_info_.Add(InlinedInfo(caller, target, inlining_depth_, \ | 114 inlined_info_.Add(InlinedInfo(caller, target, inlining_depth_, \ |
| 115 instance_call, comment)); \ | 115 instance_call, comment)); \ |
| 116 } \ | 116 } \ |
| 117 } while (false) | 117 } while (false) |
| 118 | 118 |
| 119 | |
| 120 // Test if a call is recursive by looking in the deoptimization environment. | 119 // Test if a call is recursive by looking in the deoptimization environment. |
| 121 static bool IsCallRecursive(const Function& function, Definition* call) { | 120 static bool IsCallRecursive(const Function& function, Definition* call) { |
| 122 Environment* env = call->env(); | 121 Environment* env = call->env(); |
| 123 while (env != NULL) { | 122 while (env != NULL) { |
| 124 if (function.raw() == env->function().raw()) { | 123 if (function.raw() == env->function().raw()) { |
| 125 return true; | 124 return true; |
| 126 } | 125 } |
| 127 env = env->outer(); | 126 env = env->outer(); |
| 128 } | 127 } |
| 129 return false; | 128 return false; |
| 130 } | 129 } |
| 131 | 130 |
| 132 | |
| 133 // Helper to get the default value of a formal parameter. | 131 // Helper to get the default value of a formal parameter. |
| 134 static ConstantInstr* GetDefaultValue(intptr_t i, | 132 static ConstantInstr* GetDefaultValue(intptr_t i, |
| 135 const ParsedFunction& parsed_function) { | 133 const ParsedFunction& parsed_function) { |
| 136 return new ConstantInstr(parsed_function.DefaultParameterValueAt(i)); | 134 return new ConstantInstr(parsed_function.DefaultParameterValueAt(i)); |
| 137 } | 135 } |
| 138 | 136 |
| 139 | |
| 140 // Pair of an argument name and its value. | 137 // Pair of an argument name and its value. |
| 141 struct NamedArgument { | 138 struct NamedArgument { |
| 142 String* name; | 139 String* name; |
| 143 Value* value; | 140 Value* value; |
| 144 NamedArgument(String* name, Value* value) : name(name), value(value) {} | 141 NamedArgument(String* name, Value* value) : name(name), value(value) {} |
| 145 }; | 142 }; |
| 146 | 143 |
| 147 | |
| 148 // Helper to collect information about a callee graph when considering it for | 144 // Helper to collect information about a callee graph when considering it for |
| 149 // inlining. | 145 // inlining. |
| 150 class GraphInfoCollector : public ValueObject { | 146 class GraphInfoCollector : public ValueObject { |
| 151 public: | 147 public: |
| 152 GraphInfoCollector() : call_site_count_(0), instruction_count_(0) {} | 148 GraphInfoCollector() : call_site_count_(0), instruction_count_(0) {} |
| 153 | 149 |
| 154 void Collect(const FlowGraph& graph) { | 150 void Collect(const FlowGraph& graph) { |
| 155 call_site_count_ = 0; | 151 call_site_count_ = 0; |
| 156 instruction_count_ = 0; | 152 instruction_count_ = 0; |
| 157 for (BlockIterator block_it = graph.postorder_iterator(); !block_it.Done(); | 153 for (BlockIterator block_it = graph.postorder_iterator(); !block_it.Done(); |
| (...skipping 29 matching lines...) Expand all Loading... |
| 187 } | 183 } |
| 188 | 184 |
| 189 intptr_t call_site_count() const { return call_site_count_; } | 185 intptr_t call_site_count() const { return call_site_count_; } |
| 190 intptr_t instruction_count() const { return instruction_count_; } | 186 intptr_t instruction_count() const { return instruction_count_; } |
| 191 | 187 |
| 192 private: | 188 private: |
| 193 intptr_t call_site_count_; | 189 intptr_t call_site_count_; |
| 194 intptr_t instruction_count_; | 190 intptr_t instruction_count_; |
| 195 }; | 191 }; |
| 196 | 192 |
| 197 | |
| 198 // Structure for collecting inline data needed to print inlining tree. | 193 // Structure for collecting inline data needed to print inlining tree. |
| 199 struct InlinedInfo { | 194 struct InlinedInfo { |
| 200 const Function* caller; | 195 const Function* caller; |
| 201 const Function* inlined; | 196 const Function* inlined; |
| 202 intptr_t inlined_depth; | 197 intptr_t inlined_depth; |
| 203 const Definition* call_instr; | 198 const Definition* call_instr; |
| 204 const char* bailout_reason; | 199 const char* bailout_reason; |
| 205 InlinedInfo(const Function* caller_function, | 200 InlinedInfo(const Function* caller_function, |
| 206 const Function* inlined_function, | 201 const Function* inlined_function, |
| 207 const intptr_t depth, | 202 const intptr_t depth, |
| 208 const Definition* call, | 203 const Definition* call, |
| 209 const char* reason) | 204 const char* reason) |
| 210 : caller(caller_function), | 205 : caller(caller_function), |
| 211 inlined(inlined_function), | 206 inlined(inlined_function), |
| 212 inlined_depth(depth), | 207 inlined_depth(depth), |
| 213 call_instr(call), | 208 call_instr(call), |
| 214 bailout_reason(reason) {} | 209 bailout_reason(reason) {} |
| 215 }; | 210 }; |
| 216 | 211 |
| 217 | |
| 218 // A collection of call sites to consider for inlining. | 212 // A collection of call sites to consider for inlining. |
| 219 class CallSites : public ValueObject { | 213 class CallSites : public ValueObject { |
| 220 public: | 214 public: |
| 221 explicit CallSites(FlowGraph* flow_graph, intptr_t threshold) | 215 explicit CallSites(FlowGraph* flow_graph, intptr_t threshold) |
| 222 : inlining_depth_threshold_(threshold), | 216 : inlining_depth_threshold_(threshold), |
| 223 static_calls_(), | 217 static_calls_(), |
| 224 closure_calls_(), | 218 closure_calls_(), |
| 225 instance_calls_() {} | 219 instance_calls_() {} |
| 226 | 220 |
| 227 struct InstanceCallInfo { | 221 struct InstanceCallInfo { |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 // TODO(srdjan): Add data for closure calls. | 339 // TODO(srdjan): Add data for closure calls. |
| 346 } | 340 } |
| 347 if (call != NULL) { | 341 if (call != NULL) { |
| 348 inlined_info->Add( | 342 inlined_info->Add( |
| 349 InlinedInfo(caller, &target, depth + 1, call, "Too deep")); | 343 InlinedInfo(caller, &target, depth + 1, call, "Too deep")); |
| 350 } | 344 } |
| 351 } | 345 } |
| 352 } | 346 } |
| 353 } | 347 } |
| 354 | 348 |
| 355 | |
| 356 void FindCallSites(FlowGraph* graph, | 349 void FindCallSites(FlowGraph* graph, |
| 357 intptr_t depth, | 350 intptr_t depth, |
| 358 GrowableArray<InlinedInfo>* inlined_info) { | 351 GrowableArray<InlinedInfo>* inlined_info) { |
| 359 ASSERT(graph != NULL); | 352 ASSERT(graph != NULL); |
| 360 if (depth > inlining_depth_threshold_) { | 353 if (depth > inlining_depth_threshold_) { |
| 361 if (FLAG_print_inlining_tree) { | 354 if (FLAG_print_inlining_tree) { |
| 362 RecordAllNotInlinedFunction(graph, depth, inlined_info); | 355 RecordAllNotInlinedFunction(graph, depth, inlined_info); |
| 363 } | 356 } |
| 364 return; | 357 return; |
| 365 } | 358 } |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 422 | 415 |
| 423 private: | 416 private: |
| 424 intptr_t inlining_depth_threshold_; | 417 intptr_t inlining_depth_threshold_; |
| 425 GrowableArray<StaticCallInfo> static_calls_; | 418 GrowableArray<StaticCallInfo> static_calls_; |
| 426 GrowableArray<ClosureCallInfo> closure_calls_; | 419 GrowableArray<ClosureCallInfo> closure_calls_; |
| 427 GrowableArray<InstanceCallInfo> instance_calls_; | 420 GrowableArray<InstanceCallInfo> instance_calls_; |
| 428 | 421 |
| 429 DISALLOW_COPY_AND_ASSIGN(CallSites); | 422 DISALLOW_COPY_AND_ASSIGN(CallSites); |
| 430 }; | 423 }; |
| 431 | 424 |
| 432 | |
| 433 struct InlinedCallData { | 425 struct InlinedCallData { |
| 434 InlinedCallData(Definition* call, | 426 InlinedCallData(Definition* call, |
| 435 intptr_t first_param_index, // 1 if type args are passed. | 427 intptr_t first_param_index, // 1 if type args are passed. |
| 436 GrowableArray<Value*>* arguments, | 428 GrowableArray<Value*>* arguments, |
| 437 const Function& caller, | 429 const Function& caller, |
| 438 intptr_t caller_inlining_id) | 430 intptr_t caller_inlining_id) |
| 439 : call(call), | 431 : call(call), |
| 440 first_param_index(first_param_index), | 432 first_param_index(first_param_index), |
| 441 arguments(arguments), | 433 arguments(arguments), |
| 442 callee_graph(NULL), | 434 callee_graph(NULL), |
| 443 parameter_stubs(NULL), | 435 parameter_stubs(NULL), |
| 444 exit_collector(NULL), | 436 exit_collector(NULL), |
| 445 caller(caller), | 437 caller(caller), |
| 446 caller_inlining_id(caller_inlining_id) {} | 438 caller_inlining_id(caller_inlining_id) {} |
| 447 | 439 |
| 448 Definition* call; | 440 Definition* call; |
| 449 const intptr_t first_param_index; | 441 const intptr_t first_param_index; |
| 450 GrowableArray<Value*>* arguments; | 442 GrowableArray<Value*>* arguments; |
| 451 FlowGraph* callee_graph; | 443 FlowGraph* callee_graph; |
| 452 ZoneGrowableArray<Definition*>* parameter_stubs; | 444 ZoneGrowableArray<Definition*>* parameter_stubs; |
| 453 InlineExitCollector* exit_collector; | 445 InlineExitCollector* exit_collector; |
| 454 const Function& caller; | 446 const Function& caller; |
| 455 const intptr_t caller_inlining_id; | 447 const intptr_t caller_inlining_id; |
| 456 }; | 448 }; |
| 457 | 449 |
| 458 | |
| 459 class CallSiteInliner; | 450 class CallSiteInliner; |
| 460 | 451 |
| 461 class PolymorphicInliner : public ValueObject { | 452 class PolymorphicInliner : public ValueObject { |
| 462 public: | 453 public: |
| 463 PolymorphicInliner(CallSiteInliner* owner, | 454 PolymorphicInliner(CallSiteInliner* owner, |
| 464 PolymorphicInstanceCallInstr* call, | 455 PolymorphicInstanceCallInstr* call, |
| 465 const Function& caller_function, | 456 const Function& caller_function, |
| 466 intptr_t caller_inlining_id); | 457 intptr_t caller_inlining_id); |
| 467 | 458 |
| 468 void Inline(); | 459 void Inline(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 490 // The non_inlined_variants_ can be used in a long-lived instruction object, | 481 // The non_inlined_variants_ can be used in a long-lived instruction object, |
| 491 // so they are not embedded into the shorter-lived PolymorphicInliner object. | 482 // so they are not embedded into the shorter-lived PolymorphicInliner object. |
| 492 CallTargets* non_inlined_variants_; | 483 CallTargets* non_inlined_variants_; |
| 493 GrowableArray<BlockEntryInstr*> inlined_entries_; | 484 GrowableArray<BlockEntryInstr*> inlined_entries_; |
| 494 InlineExitCollector* exit_collector_; | 485 InlineExitCollector* exit_collector_; |
| 495 | 486 |
| 496 const Function& caller_function_; | 487 const Function& caller_function_; |
| 497 const intptr_t caller_inlining_id_; | 488 const intptr_t caller_inlining_id_; |
| 498 }; | 489 }; |
| 499 | 490 |
| 500 | |
| 501 static bool HasAnnotation(const Function& function, const char* annotation) { | 491 static bool HasAnnotation(const Function& function, const char* annotation) { |
| 502 const Class& owner = Class::Handle(function.Owner()); | 492 const Class& owner = Class::Handle(function.Owner()); |
| 503 const Library& library = Library::Handle(owner.library()); | 493 const Library& library = Library::Handle(owner.library()); |
| 504 const Array& metadata = | 494 const Array& metadata = |
| 505 Array::Cast(Object::Handle(library.GetMetadata(function))); | 495 Array::Cast(Object::Handle(library.GetMetadata(function))); |
| 506 | 496 |
| 507 if (metadata.Length() > 0) { | 497 if (metadata.Length() > 0) { |
| 508 Object& val = Object::Handle(); | 498 Object& val = Object::Handle(); |
| 509 for (intptr_t i = 0; i < metadata.Length(); i++) { | 499 for (intptr_t i = 0; i < metadata.Length(); i++) { |
| 510 val = metadata.At(i); | 500 val = metadata.At(i); |
| 511 if (val.IsString() && String::Cast(val).Equals(annotation)) { | 501 if (val.IsString() && String::Cast(val).Equals(annotation)) { |
| 512 return true; | 502 return true; |
| 513 } | 503 } |
| 514 } | 504 } |
| 515 } | 505 } |
| 516 return false; | 506 return false; |
| 517 } | 507 } |
| 518 | 508 |
| 519 | |
| 520 static void ReplaceParameterStubs(Zone* zone, | 509 static void ReplaceParameterStubs(Zone* zone, |
| 521 FlowGraph* caller_graph, | 510 FlowGraph* caller_graph, |
| 522 InlinedCallData* call_data, | 511 InlinedCallData* call_data, |
| 523 const TargetInfo* target_info) { | 512 const TargetInfo* target_info) { |
| 524 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); | 513 CSTAT_TIMER_SCOPE(Thread::Current(), graphinliner_subst_timer); |
| 525 const bool is_polymorphic = call_data->call->IsPolymorphicInstanceCall(); | 514 const bool is_polymorphic = call_data->call->IsPolymorphicInstanceCall(); |
| 526 ASSERT(is_polymorphic == (target_info != NULL)); | 515 ASSERT(is_polymorphic == (target_info != NULL)); |
| 527 FlowGraph* callee_graph = call_data->callee_graph; | 516 FlowGraph* callee_graph = call_data->callee_graph; |
| 528 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); | 517 TargetEntryInstr* callee_entry = callee_graph->graph_entry()->normal_entry(); |
| 529 | 518 |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 599 } | 588 } |
| 600 param->ReplaceUsesWith(type_args); | 589 param->ReplaceUsesWith(type_args); |
| 601 } | 590 } |
| 602 } | 591 } |
| 603 } | 592 } |
| 604 | 593 |
| 605 // Check that inlining maintains use lists. | 594 // Check that inlining maintains use lists. |
| 606 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph->VerifyUseLists()); | 595 DEBUG_ASSERT(!FLAG_verify_compiler || caller_graph->VerifyUseLists()); |
| 607 } | 596 } |
| 608 | 597 |
| 609 | |
| 610 class CallSiteInliner : public ValueObject { | 598 class CallSiteInliner : public ValueObject { |
| 611 public: | 599 public: |
| 612 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) | 600 explicit CallSiteInliner(FlowGraphInliner* inliner, intptr_t threshold) |
| 613 : inliner_(inliner), | 601 : inliner_(inliner), |
| 614 caller_graph_(inliner->flow_graph()), | 602 caller_graph_(inliner->flow_graph()), |
| 615 inlined_(false), | 603 inlined_(false), |
| 616 initial_size_(inliner->flow_graph()->InstructionCount()), | 604 initial_size_(inliner->flow_graph()->InstructionCount()), |
| 617 inlined_size_(0), | 605 inlined_size_(0), |
| 618 inlined_recursive_call_(false), | 606 inlined_recursive_call_(false), |
| 619 inlining_depth_(1), | 607 inlining_depth_(1), |
| (...skipping 256 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 876 CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer); | 864 CSTAT_TIMER_SCOPE(thread(), graphinliner_parse_timer); |
| 877 parsed_function = GetParsedFunction(function, &in_cache); | 865 parsed_function = GetParsedFunction(function, &in_cache); |
| 878 if (!function.CanBeInlined()) { | 866 if (!function.CanBeInlined()) { |
| 879 // As a side effect of parsing the function, it may be marked | 867 // As a side effect of parsing the function, it may be marked |
| 880 // as not inlinable. This happens for async and async* functions | 868 // as not inlinable. This happens for async and async* functions |
| 881 // when causal stack traces are being tracked. | 869 // when causal stack traces are being tracked. |
| 882 return false; | 870 return false; |
| 883 } | 871 } |
| 884 } | 872 } |
| 885 | 873 |
| 886 | |
| 887 // Build the callee graph. | 874 // Build the callee graph. |
| 888 InlineExitCollector* exit_collector = | 875 InlineExitCollector* exit_collector = |
| 889 new (Z) InlineExitCollector(caller_graph_, call); | 876 new (Z) InlineExitCollector(caller_graph_, call); |
| 890 FlowGraph* callee_graph; | 877 FlowGraph* callee_graph; |
| 891 if (UseKernelFrontEndFor(parsed_function)) { | 878 if (UseKernelFrontEndFor(parsed_function)) { |
| 892 kernel::FlowGraphBuilder builder( | 879 kernel::FlowGraphBuilder builder( |
| 893 parsed_function->function().kernel_offset(), parsed_function, | 880 parsed_function->function().kernel_offset(), parsed_function, |
| 894 *ic_data_array, /* not building var desc */ NULL, exit_collector, | 881 *ic_data_array, /* not building var desc */ NULL, exit_collector, |
| 895 Compiler::kNoOSRDeoptId, caller_graph_->max_block_id() + 1); | 882 Compiler::kNoOSRDeoptId, caller_graph_->max_block_id() + 1); |
| 896 { | 883 { |
| (...skipping 581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1478 intptr_t inlining_recursion_depth_; | 1465 intptr_t inlining_recursion_depth_; |
| 1479 intptr_t inlining_depth_threshold_; | 1466 intptr_t inlining_depth_threshold_; |
| 1480 CallSites* collected_call_sites_; | 1467 CallSites* collected_call_sites_; |
| 1481 CallSites* inlining_call_sites_; | 1468 CallSites* inlining_call_sites_; |
| 1482 GrowableArray<ParsedFunction*> function_cache_; | 1469 GrowableArray<ParsedFunction*> function_cache_; |
| 1483 GrowableArray<InlinedInfo> inlined_info_; | 1470 GrowableArray<InlinedInfo> inlined_info_; |
| 1484 | 1471 |
| 1485 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 1472 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
| 1486 }; | 1473 }; |
| 1487 | 1474 |
| 1488 | |
| 1489 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1475 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
| 1490 PolymorphicInstanceCallInstr* call, | 1476 PolymorphicInstanceCallInstr* call, |
| 1491 const Function& caller_function, | 1477 const Function& caller_function, |
| 1492 intptr_t caller_inlining_id) | 1478 intptr_t caller_inlining_id) |
| 1493 : owner_(owner), | 1479 : owner_(owner), |
| 1494 call_(call), | 1480 call_(call), |
| 1495 num_variants_(call->NumberOfChecks()), | 1481 num_variants_(call->NumberOfChecks()), |
| 1496 variants_(call->targets_), | 1482 variants_(call->targets_), |
| 1497 inlined_variants_(zone()), | 1483 inlined_variants_(zone()), |
| 1498 non_inlined_variants_(new (zone()) CallTargets(zone())), | 1484 non_inlined_variants_(new (zone()) CallTargets(zone())), |
| 1499 inlined_entries_(num_variants_), | 1485 inlined_entries_(num_variants_), |
| 1500 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), | 1486 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), |
| 1501 caller_function_(caller_function), | 1487 caller_function_(caller_function), |
| 1502 caller_inlining_id_(caller_inlining_id) {} | 1488 caller_inlining_id_(caller_inlining_id) {} |
| 1503 | 1489 |
| 1504 | |
| 1505 Isolate* PolymorphicInliner::isolate() const { | 1490 Isolate* PolymorphicInliner::isolate() const { |
| 1506 return owner_->caller_graph()->isolate(); | 1491 return owner_->caller_graph()->isolate(); |
| 1507 } | 1492 } |
| 1508 | 1493 |
| 1509 | |
| 1510 Zone* PolymorphicInliner::zone() const { | 1494 Zone* PolymorphicInliner::zone() const { |
| 1511 return owner_->caller_graph()->zone(); | 1495 return owner_->caller_graph()->zone(); |
| 1512 } | 1496 } |
| 1513 | 1497 |
| 1514 | |
| 1515 intptr_t PolymorphicInliner::AllocateBlockId() const { | 1498 intptr_t PolymorphicInliner::AllocateBlockId() const { |
| 1516 return owner_->caller_graph()->allocate_block_id(); | 1499 return owner_->caller_graph()->allocate_block_id(); |
| 1517 } | 1500 } |
| 1518 | 1501 |
| 1519 | |
| 1520 // Inlined bodies are shared if two different class ids have the same | 1502 // Inlined bodies are shared if two different class ids have the same |
| 1521 // inlined target. This sharing is represented by using three different | 1503 // inlined target. This sharing is represented by using three different |
| 1522 // types of entries in the inlined_entries_ array: | 1504 // types of entries in the inlined_entries_ array: |
| 1523 // | 1505 // |
| 1524 // * GraphEntry: the inlined body is not shared. | 1506 // * GraphEntry: the inlined body is not shared. |
| 1525 // | 1507 // |
| 1526 // * TargetEntry: the inlined body is shared and this is the first variant. | 1508 // * TargetEntry: the inlined body is shared and this is the first variant. |
| 1527 // | 1509 // |
| 1528 // * JoinEntry: the inlined body is shared and this is a subsequent variant. | 1510 // * JoinEntry: the inlined body is shared and this is a subsequent variant. |
| 1529 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { | 1511 bool PolymorphicInliner::CheckInlinedDuplicate(const Function& target) { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1570 inlined_entries_[i]->last_instruction()->SuccessorAt(0); | 1552 inlined_entries_[i]->last_instruction()->SuccessorAt(0); |
| 1571 ASSERT(join->IsJoinEntry()); | 1553 ASSERT(join->IsJoinEntry()); |
| 1572 inlined_entries_.Add(join); | 1554 inlined_entries_.Add(join); |
| 1573 return true; | 1555 return true; |
| 1574 } | 1556 } |
| 1575 } | 1557 } |
| 1576 | 1558 |
| 1577 return false; | 1559 return false; |
| 1578 } | 1560 } |
| 1579 | 1561 |
| 1580 | |
| 1581 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { | 1562 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { |
| 1582 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { | 1563 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { |
| 1583 if (target.raw() == non_inlined_variants_->TargetAt(i)->target->raw()) { | 1564 if (target.raw() == non_inlined_variants_->TargetAt(i)->target->raw()) { |
| 1584 return true; | 1565 return true; |
| 1585 } | 1566 } |
| 1586 } | 1567 } |
| 1587 | 1568 |
| 1588 return false; | 1569 return false; |
| 1589 } | 1570 } |
| 1590 | 1571 |
| 1591 | |
| 1592 bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) { | 1572 bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) { |
| 1593 if ((!FLAG_precompiled_mode || | 1573 if ((!FLAG_precompiled_mode || |
| 1594 owner_->inliner_->use_speculative_inlining()) && | 1574 owner_->inliner_->use_speculative_inlining()) && |
| 1595 target_info.IsSingleCid() && | 1575 target_info.IsSingleCid() && |
| 1596 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { | 1576 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
| 1597 owner_->inlined_ = true; | 1577 owner_->inlined_ = true; |
| 1598 return true; | 1578 return true; |
| 1599 } | 1579 } |
| 1600 | 1580 |
| 1601 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1581 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 1613 FlowGraph* callee_graph = call_data.callee_graph; | 1593 FlowGraph* callee_graph = call_data.callee_graph; |
| 1614 call_data.exit_collector->PrepareGraphs(callee_graph); | 1594 call_data.exit_collector->PrepareGraphs(callee_graph); |
| 1615 inlined_entries_.Add(callee_graph->graph_entry()); | 1595 inlined_entries_.Add(callee_graph->graph_entry()); |
| 1616 exit_collector_->Union(call_data.exit_collector); | 1596 exit_collector_->Union(call_data.exit_collector); |
| 1617 | 1597 |
| 1618 ReplaceParameterStubs(zone(), owner_->caller_graph(), &call_data, | 1598 ReplaceParameterStubs(zone(), owner_->caller_graph(), &call_data, |
| 1619 &target_info); | 1599 &target_info); |
| 1620 return true; | 1600 return true; |
| 1621 } | 1601 } |
| 1622 | 1602 |
| 1623 | |
| 1624 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { | 1603 static Instruction* AppendInstruction(Instruction* first, Instruction* second) { |
| 1625 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { | 1604 for (intptr_t i = second->InputCount() - 1; i >= 0; --i) { |
| 1626 Value* input = second->InputAt(i); | 1605 Value* input = second->InputAt(i); |
| 1627 input->definition()->AddInputUse(input); | 1606 input->definition()->AddInputUse(input); |
| 1628 } | 1607 } |
| 1629 first->LinkTo(second); | 1608 first->LinkTo(second); |
| 1630 return second; | 1609 return second; |
| 1631 } | 1610 } |
| 1632 | 1611 |
| 1633 | |
| 1634 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, | 1612 bool PolymorphicInliner::TryInlineRecognizedMethod(intptr_t receiver_cid, |
| 1635 const Function& target) { | 1613 const Function& target) { |
| 1636 TargetEntryInstr* entry; | 1614 TargetEntryInstr* entry; |
| 1637 Definition* last; | 1615 Definition* last; |
| 1638 // Replace the receiver argument with a redefinition to prevent code from | 1616 // Replace the receiver argument with a redefinition to prevent code from |
| 1639 // the inlined body from being hoisted above the inlined entry. | 1617 // the inlined body from being hoisted above the inlined entry. |
| 1640 GrowableArray<Definition*> arguments(call_->ArgumentCount()); | 1618 GrowableArray<Definition*> arguments(call_->ArgumentCount()); |
| 1641 Definition* receiver = call_->ArgumentAt(0); | 1619 Definition* receiver = call_->ArgumentAt(0); |
| 1642 RedefinitionInstr* redefinition = | 1620 RedefinitionInstr* redefinition = |
| 1643 new (Z) RedefinitionInstr(new (Z) Value(receiver)); | 1621 new (Z) RedefinitionInstr(new (Z) Value(receiver)); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1666 GraphEntryInstr* graph_entry = new (Z) | 1644 GraphEntryInstr* graph_entry = new (Z) |
| 1667 GraphEntryInstr(*temp_parsed_function, entry, Compiler::kNoOSRDeoptId); | 1645 GraphEntryInstr(*temp_parsed_function, entry, Compiler::kNoOSRDeoptId); |
| 1668 // Update polymorphic inliner state. | 1646 // Update polymorphic inliner state. |
| 1669 inlined_entries_.Add(graph_entry); | 1647 inlined_entries_.Add(graph_entry); |
| 1670 exit_collector_->Union(exit_collector); | 1648 exit_collector_->Union(exit_collector); |
| 1671 return true; | 1649 return true; |
| 1672 } | 1650 } |
| 1673 return false; | 1651 return false; |
| 1674 } | 1652 } |
| 1675 | 1653 |
| 1676 | |
| 1677 // Build a DAG to dispatch to the inlined function bodies. Load the class | 1654 // Build a DAG to dispatch to the inlined function bodies. Load the class |
| 1678 // id of the receiver and make explicit comparisons for each inlined body, | 1655 // id of the receiver and make explicit comparisons for each inlined body, |
| 1679 // in frequency order. If all variants are inlined, the entry to the last | 1656 // in frequency order. If all variants are inlined, the entry to the last |
| 1680 // inlined body is guarded by a CheckClassId instruction which can deopt. | 1657 // inlined body is guarded by a CheckClassId instruction which can deopt. |
| 1681 // If not all variants are inlined, we add a PolymorphicInstanceCall | 1658 // If not all variants are inlined, we add a PolymorphicInstanceCall |
| 1682 // instruction to handle the non-inlined variants. | 1659 // instruction to handle the non-inlined variants. |
| 1683 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { | 1660 TargetEntryInstr* PolymorphicInliner::BuildDecisionGraph() { |
| 1684 const intptr_t try_idx = call_->GetBlock()->try_index(); | 1661 const intptr_t try_idx = call_->GetBlock()->try_index(); |
| 1685 | 1662 |
| 1686 // Start with a fresh target entry. | 1663 // Start with a fresh target entry. |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1912 // Remove push arguments of the call. | 1889 // Remove push arguments of the call. |
| 1913 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1890 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
| 1914 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1891 PushArgumentInstr* push = call_->PushArgumentAt(i); |
| 1915 push->ReplaceUsesWith(push->value()->definition()); | 1892 push->ReplaceUsesWith(push->value()->definition()); |
| 1916 push->RemoveFromGraph(); | 1893 push->RemoveFromGraph(); |
| 1917 } | 1894 } |
| 1918 } | 1895 } |
| 1919 return entry; | 1896 return entry; |
| 1920 } | 1897 } |
| 1921 | 1898 |
| 1922 | |
| 1923 static void TracePolyInlining(const CallTargets& targets, | 1899 static void TracePolyInlining(const CallTargets& targets, |
| 1924 intptr_t idx, | 1900 intptr_t idx, |
| 1925 intptr_t total, | 1901 intptr_t total, |
| 1926 const char* message) { | 1902 const char* message) { |
| 1927 String& name = | 1903 String& name = |
| 1928 String::Handle(targets.TargetAt(idx)->target->QualifiedUserVisibleName()); | 1904 String::Handle(targets.TargetAt(idx)->target->QualifiedUserVisibleName()); |
| 1929 int percent = total == 0 ? 0 : (100 * targets.TargetAt(idx)->count) / total; | 1905 int percent = total == 0 ? 0 : (100 * targets.TargetAt(idx)->count) / total; |
| 1930 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", | 1906 THR_Print("%s cid %" Pd "-%" Pd ": %" Pd "/%" Pd " %d%% %s\n", |
| 1931 name.ToCString(), targets[idx].cid_start, targets[idx].cid_end, | 1907 name.ToCString(), targets[idx].cid_start, targets[idx].cid_end, |
| 1932 targets.TargetAt(idx)->count, total, percent, message); | 1908 targets.TargetAt(idx)->count, total, percent, message); |
| 1933 } | 1909 } |
| 1934 | 1910 |
| 1935 | |
| 1936 bool PolymorphicInliner::trace_inlining() const { | 1911 bool PolymorphicInliner::trace_inlining() const { |
| 1937 return owner_->trace_inlining(); | 1912 return owner_->trace_inlining(); |
| 1938 } | 1913 } |
| 1939 | 1914 |
| 1940 | |
| 1941 void PolymorphicInliner::Inline() { | 1915 void PolymorphicInliner::Inline() { |
| 1942 ASSERT(&variants_ == &call_->targets_); | 1916 ASSERT(&variants_ == &call_->targets_); |
| 1943 | 1917 |
| 1944 intptr_t total = call_->total_call_count(); | 1918 intptr_t total = call_->total_call_count(); |
| 1945 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { | 1919 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { |
| 1946 TargetInfo* info = variants_.TargetAt(var_idx); | 1920 TargetInfo* info = variants_.TargetAt(var_idx); |
| 1947 if (variants_.length() > FLAG_max_polymorphic_checks) { | 1921 if (variants_.length() > FLAG_max_polymorphic_checks) { |
| 1948 non_inlined_variants_->Add(info); | 1922 non_inlined_variants_->Add(info); |
| 1949 continue; | 1923 continue; |
| 1950 } | 1924 } |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2012 | 1986 |
| 2013 // If there are no inlined variants, leave the call in place. | 1987 // If there are no inlined variants, leave the call in place. |
| 2014 if (inlined_variants_.is_empty()) return; | 1988 if (inlined_variants_.is_empty()) return; |
| 2015 | 1989 |
| 2016 // Now build a decision tree (a DAG because of shared inline variants) and | 1990 // Now build a decision tree (a DAG because of shared inline variants) and |
| 2017 // inline it at the call site. | 1991 // inline it at the call site. |
| 2018 TargetEntryInstr* entry = BuildDecisionGraph(); | 1992 TargetEntryInstr* entry = BuildDecisionGraph(); |
| 2019 exit_collector_->ReplaceCall(entry); | 1993 exit_collector_->ReplaceCall(entry); |
| 2020 } | 1994 } |
| 2021 | 1995 |
| 2022 | |
| 2023 static uint16_t ClampUint16(intptr_t v) { | 1996 static uint16_t ClampUint16(intptr_t v) { |
| 2024 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); | 1997 return (v > 0xFFFF) ? 0xFFFF : static_cast<uint16_t>(v); |
| 2025 } | 1998 } |
| 2026 | 1999 |
| 2027 | |
| 2028 static bool ShouldTraceInlining(FlowGraph* flow_graph) { | 2000 static bool ShouldTraceInlining(FlowGraph* flow_graph) { |
| 2029 const Function& top = flow_graph->parsed_function().function(); | 2001 const Function& top = flow_graph->parsed_function().function(); |
| 2030 return FLAG_trace_inlining && FlowGraphPrinter::ShouldPrint(top); | 2002 return FLAG_trace_inlining && FlowGraphPrinter::ShouldPrint(top); |
| 2031 } | 2003 } |
| 2032 | 2004 |
| 2033 | |
| 2034 FlowGraphInliner::FlowGraphInliner( | 2005 FlowGraphInliner::FlowGraphInliner( |
| 2035 FlowGraph* flow_graph, | 2006 FlowGraph* flow_graph, |
| 2036 GrowableArray<const Function*>* inline_id_to_function, | 2007 GrowableArray<const Function*>* inline_id_to_function, |
| 2037 GrowableArray<TokenPosition>* inline_id_to_token_pos, | 2008 GrowableArray<TokenPosition>* inline_id_to_token_pos, |
| 2038 GrowableArray<intptr_t>* caller_inline_id, | 2009 GrowableArray<intptr_t>* caller_inline_id, |
| 2039 bool use_speculative_inlining, | 2010 bool use_speculative_inlining, |
| 2040 GrowableArray<intptr_t>* inlining_black_list, | 2011 GrowableArray<intptr_t>* inlining_black_list, |
| 2041 Precompiler* precompiler) | 2012 Precompiler* precompiler) |
| 2042 : flow_graph_(flow_graph), | 2013 : flow_graph_(flow_graph), |
| 2043 inline_id_to_function_(inline_id_to_function), | 2014 inline_id_to_function_(inline_id_to_function), |
| 2044 inline_id_to_token_pos_(inline_id_to_token_pos), | 2015 inline_id_to_token_pos_(inline_id_to_token_pos), |
| 2045 caller_inline_id_(caller_inline_id), | 2016 caller_inline_id_(caller_inline_id), |
| 2046 trace_inlining_(ShouldTraceInlining(flow_graph)), | 2017 trace_inlining_(ShouldTraceInlining(flow_graph)), |
| 2047 use_speculative_inlining_(use_speculative_inlining), | 2018 use_speculative_inlining_(use_speculative_inlining), |
| 2048 inlining_black_list_(inlining_black_list), | 2019 inlining_black_list_(inlining_black_list), |
| 2049 precompiler_(precompiler) { | 2020 precompiler_(precompiler) { |
| 2050 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); | 2021 ASSERT(!use_speculative_inlining || (inlining_black_list != NULL)); |
| 2051 } | 2022 } |
| 2052 | 2023 |
| 2053 | |
| 2054 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { | 2024 void FlowGraphInliner::CollectGraphInfo(FlowGraph* flow_graph, bool force) { |
| 2055 const Function& function = flow_graph->function(); | 2025 const Function& function = flow_graph->function(); |
| 2056 if (force || (function.optimized_instruction_count() == 0)) { | 2026 if (force || (function.optimized_instruction_count() == 0)) { |
| 2057 GraphInfoCollector info; | 2027 GraphInfoCollector info; |
| 2058 info.Collect(*flow_graph); | 2028 info.Collect(*flow_graph); |
| 2059 | 2029 |
| 2060 function.set_optimized_instruction_count( | 2030 function.set_optimized_instruction_count( |
| 2061 ClampUint16(info.instruction_count())); | 2031 ClampUint16(info.instruction_count())); |
| 2062 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); | 2032 function.set_optimized_call_site_count(ClampUint16(info.call_site_count())); |
| 2063 } | 2033 } |
| 2064 } | 2034 } |
| 2065 | 2035 |
| 2066 | |
| 2067 // TODO(srdjan): This is only needed when disassembling and/or profiling. | 2036 // TODO(srdjan): This is only needed when disassembling and/or profiling. |
| 2068 // Sets inlining id for all instructions of this flow-graph, as well for the | 2037 // Sets inlining id for all instructions of this flow-graph, as well for the |
| 2069 // FlowGraph itself. | 2038 // FlowGraph itself. |
| 2070 void FlowGraphInliner::SetInliningId(FlowGraph* flow_graph, | 2039 void FlowGraphInliner::SetInliningId(FlowGraph* flow_graph, |
| 2071 intptr_t inlining_id) { | 2040 intptr_t inlining_id) { |
| 2072 ASSERT(flow_graph->inlining_id() < 0); | 2041 ASSERT(flow_graph->inlining_id() < 0); |
| 2073 flow_graph->set_inlining_id(inlining_id); | 2042 flow_graph->set_inlining_id(inlining_id); |
| 2074 for (BlockIterator block_it = flow_graph->postorder_iterator(); | 2043 for (BlockIterator block_it = flow_graph->postorder_iterator(); |
| 2075 !block_it.Done(); block_it.Advance()) { | 2044 !block_it.Done(); block_it.Advance()) { |
| 2076 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); | 2045 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); |
| 2077 it.Advance()) { | 2046 it.Advance()) { |
| 2078 Instruction* current = it.Current(); | 2047 Instruction* current = it.Current(); |
| 2079 // Do not overwrite owner function. | 2048 // Do not overwrite owner function. |
| 2080 ASSERT(!current->has_inlining_id()); | 2049 ASSERT(!current->has_inlining_id()); |
| 2081 current->set_inlining_id(inlining_id); | 2050 current->set_inlining_id(inlining_id); |
| 2082 } | 2051 } |
| 2083 } | 2052 } |
| 2084 } | 2053 } |
| 2085 | 2054 |
| 2086 | |
| 2087 // Use function name to determine if inlineable operator. | 2055 // Use function name to determine if inlineable operator. |
| 2088 // Add names as necessary. | 2056 // Add names as necessary. |
| 2089 static bool IsInlineableOperator(const Function& function) { | 2057 static bool IsInlineableOperator(const Function& function) { |
| 2090 return (function.name() == Symbols::IndexToken().raw()) || | 2058 return (function.name() == Symbols::IndexToken().raw()) || |
| 2091 (function.name() == Symbols::AssignIndexToken().raw()) || | 2059 (function.name() == Symbols::AssignIndexToken().raw()) || |
| 2092 (function.name() == Symbols::Plus().raw()) || | 2060 (function.name() == Symbols::Plus().raw()) || |
| 2093 (function.name() == Symbols::Minus().raw()); | 2061 (function.name() == Symbols::Minus().raw()); |
| 2094 } | 2062 } |
| 2095 | 2063 |
| 2096 | |
| 2097 bool FlowGraphInliner::AlwaysInline(const Function& function) { | 2064 bool FlowGraphInliner::AlwaysInline(const Function& function) { |
| 2098 const char* kAlwaysInlineAnnotation = "AlwaysInline"; | 2065 const char* kAlwaysInlineAnnotation = "AlwaysInline"; |
| 2099 if (FLAG_enable_inlining_annotations && | 2066 if (FLAG_enable_inlining_annotations && |
| 2100 HasAnnotation(function, kAlwaysInlineAnnotation)) { | 2067 HasAnnotation(function, kAlwaysInlineAnnotation)) { |
| 2101 TRACE_INLINING( | 2068 TRACE_INLINING( |
| 2102 THR_Print("AlwaysInline annotation for %s\n", function.ToCString())); | 2069 THR_Print("AlwaysInline annotation for %s\n", function.ToCString())); |
| 2103 return true; | 2070 return true; |
| 2104 } | 2071 } |
| 2105 | 2072 |
| 2106 if (function.IsDispatcherOrImplicitAccessor()) { | 2073 if (function.IsDispatcherOrImplicitAccessor()) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2117 IsInlineableOperator(function) || | 2084 IsInlineableOperator(function) || |
| 2118 (function.kind() == RawFunction::kConstructor)) { | 2085 (function.kind() == RawFunction::kConstructor)) { |
| 2119 const intptr_t count = function.optimized_instruction_count(); | 2086 const intptr_t count = function.optimized_instruction_count(); |
| 2120 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { | 2087 if ((count != 0) && (count < FLAG_inline_getters_setters_smaller_than)) { |
| 2121 return true; | 2088 return true; |
| 2122 } | 2089 } |
| 2123 } | 2090 } |
| 2124 return MethodRecognizer::AlwaysInline(function); | 2091 return MethodRecognizer::AlwaysInline(function); |
| 2125 } | 2092 } |
| 2126 | 2093 |
| 2127 | |
| 2128 void FlowGraphInliner::Inline() { | 2094 void FlowGraphInliner::Inline() { |
| 2129 // Collect graph info and store it on the function. | 2095 // Collect graph info and store it on the function. |
| 2130 // We might later use it for an early bailout from the inlining. | 2096 // We might later use it for an early bailout from the inlining. |
| 2131 CollectGraphInfo(flow_graph_); | 2097 CollectGraphInfo(flow_graph_); |
| 2132 | 2098 |
| 2133 const Function& top = flow_graph_->function(); | 2099 const Function& top = flow_graph_->function(); |
| 2134 if ((FLAG_inlining_filter != NULL) && | 2100 if ((FLAG_inlining_filter != NULL) && |
| 2135 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { | 2101 (strstr(top.ToFullyQualifiedCString(), FLAG_inlining_filter) == NULL)) { |
| 2136 return; | 2102 return; |
| 2137 } | 2103 } |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2169 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { | 2135 (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized)) { |
| 2170 THR_Print("After Inlining of %s\n", | 2136 THR_Print("After Inlining of %s\n", |
| 2171 flow_graph_->function().ToFullyQualifiedCString()); | 2137 flow_graph_->function().ToFullyQualifiedCString()); |
| 2172 FlowGraphPrinter printer(*flow_graph_); | 2138 FlowGraphPrinter printer(*flow_graph_); |
| 2173 printer.PrintBlocks(); | 2139 printer.PrintBlocks(); |
| 2174 } | 2140 } |
| 2175 } | 2141 } |
| 2176 } | 2142 } |
| 2177 } | 2143 } |
| 2178 | 2144 |
| 2179 | |
| 2180 intptr_t FlowGraphInliner::NextInlineId(const Function& function, | 2145 intptr_t FlowGraphInliner::NextInlineId(const Function& function, |
| 2181 TokenPosition tp, | 2146 TokenPosition tp, |
| 2182 intptr_t parent_id) { | 2147 intptr_t parent_id) { |
| 2183 const intptr_t id = inline_id_to_function_->length(); | 2148 const intptr_t id = inline_id_to_function_->length(); |
| 2184 // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper | 2149 // TODO(johnmccutchan): Do not allow IsNoSource once all nodes have proper |
| 2185 // source positions. | 2150 // source positions. |
| 2186 ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource()); | 2151 ASSERT(tp.IsReal() || tp.IsSynthetic() || tp.IsNoSource()); |
| 2187 inline_id_to_function_->Add(&function); | 2152 inline_id_to_function_->Add(&function); |
| 2188 inline_id_to_token_pos_->Add(tp); | 2153 inline_id_to_token_pos_->Add(tp); |
| 2189 caller_inline_id_->Add(parent_id); | 2154 caller_inline_id_->Add(parent_id); |
| 2190 // We always have one less token position than functions. | 2155 // We always have one less token position than functions. |
| 2191 ASSERT(inline_id_to_token_pos_->length() == | 2156 ASSERT(inline_id_to_token_pos_->length() == |
| 2192 (inline_id_to_function_->length() - 1)); | 2157 (inline_id_to_function_->length() - 1)); |
| 2193 return id; | 2158 return id; |
| 2194 } | 2159 } |
| 2195 | 2160 |
| 2196 | |
| 2197 static bool ShouldInlineSimd() { | 2161 static bool ShouldInlineSimd() { |
| 2198 return FlowGraphCompiler::SupportsUnboxedSimd128(); | 2162 return FlowGraphCompiler::SupportsUnboxedSimd128(); |
| 2199 } | 2163 } |
| 2200 | 2164 |
| 2201 | |
| 2202 static bool CanUnboxDouble() { | 2165 static bool CanUnboxDouble() { |
| 2203 return FlowGraphCompiler::SupportsUnboxedDoubles(); | 2166 return FlowGraphCompiler::SupportsUnboxedDoubles(); |
| 2204 } | 2167 } |
| 2205 | 2168 |
| 2206 | |
| 2207 static bool ShouldInlineInt64ArrayOps() { | 2169 static bool ShouldInlineInt64ArrayOps() { |
| 2208 #if defined(TARGET_ARCH_X64) | 2170 #if defined(TARGET_ARCH_X64) |
| 2209 return true; | 2171 return true; |
| 2210 #else | 2172 #else |
| 2211 return false; | 2173 return false; |
| 2212 #endif | 2174 #endif |
| 2213 } | 2175 } |
| 2214 | 2176 |
| 2215 | |
| 2216 static bool CanUnboxInt32() { | 2177 static bool CanUnboxInt32() { |
| 2217 // Int32/Uint32 can be unboxed if it fits into a smi or the platform | 2178 // Int32/Uint32 can be unboxed if it fits into a smi or the platform |
| 2218 // supports unboxed mints. | 2179 // supports unboxed mints. |
| 2219 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); | 2180 return (kSmiBits >= 32) || FlowGraphCompiler::SupportsUnboxedMints(); |
| 2220 } | 2181 } |
| 2221 | 2182 |
| 2222 | |
| 2223 // Quick access to the current one. | 2183 // Quick access to the current one. |
| 2224 #undef Z | 2184 #undef Z |
| 2225 #define Z (flow_graph->zone()) | 2185 #define Z (flow_graph->zone()) |
| 2226 | 2186 |
| 2227 static intptr_t PrepareInlineIndexedOp(FlowGraph* flow_graph, | 2187 static intptr_t PrepareInlineIndexedOp(FlowGraph* flow_graph, |
| 2228 Instruction* call, | 2188 Instruction* call, |
| 2229 intptr_t array_cid, | 2189 intptr_t array_cid, |
| 2230 Definition** array, | 2190 Definition** array, |
| 2231 Definition* index, | 2191 Definition* index, |
| 2232 Instruction** cursor) { | 2192 Instruction** cursor) { |
| (...skipping 26 matching lines...) Expand all Loading... |
| 2259 array_cid = kArrayCid; | 2219 array_cid = kArrayCid; |
| 2260 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 2220 } else if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 2261 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( | 2221 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( |
| 2262 new (Z) Value(*array), ExternalTypedData::data_offset()); | 2222 new (Z) Value(*array), ExternalTypedData::data_offset()); |
| 2263 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); | 2223 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); |
| 2264 *array = elements; | 2224 *array = elements; |
| 2265 } | 2225 } |
| 2266 return array_cid; | 2226 return array_cid; |
| 2267 } | 2227 } |
| 2268 | 2228 |
| 2269 | |
| 2270 static bool InlineGetIndexed(FlowGraph* flow_graph, | 2229 static bool InlineGetIndexed(FlowGraph* flow_graph, |
| 2271 MethodRecognizer::Kind kind, | 2230 MethodRecognizer::Kind kind, |
| 2272 Instruction* call, | 2231 Instruction* call, |
| 2273 Definition* receiver, | 2232 Definition* receiver, |
| 2274 TargetEntryInstr** entry, | 2233 TargetEntryInstr** entry, |
| 2275 Definition** last) { | 2234 Definition** last) { |
| 2276 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); | 2235 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); |
| 2277 | 2236 |
| 2278 Definition* array = receiver; | 2237 Definition* array = receiver; |
| 2279 Definition* index = call->ArgumentAt(1); | 2238 Definition* index = call->ArgumentAt(1); |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2304 | 2263 |
| 2305 if (array_cid == kTypedDataFloat32ArrayCid) { | 2264 if (array_cid == kTypedDataFloat32ArrayCid) { |
| 2306 *last = new (Z) FloatToDoubleInstr(new (Z) Value(*last), deopt_id); | 2265 *last = new (Z) FloatToDoubleInstr(new (Z) Value(*last), deopt_id); |
| 2307 flow_graph->AppendTo(cursor, *last, | 2266 flow_graph->AppendTo(cursor, *last, |
| 2308 deopt_id != Thread::kNoDeoptId ? call->env() : NULL, | 2267 deopt_id != Thread::kNoDeoptId ? call->env() : NULL, |
| 2309 FlowGraph::kValue); | 2268 FlowGraph::kValue); |
| 2310 } | 2269 } |
| 2311 return true; | 2270 return true; |
| 2312 } | 2271 } |
| 2313 | 2272 |
| 2314 | |
| 2315 static bool InlineSetIndexed(FlowGraph* flow_graph, | 2273 static bool InlineSetIndexed(FlowGraph* flow_graph, |
| 2316 MethodRecognizer::Kind kind, | 2274 MethodRecognizer::Kind kind, |
| 2317 const Function& target, | 2275 const Function& target, |
| 2318 Instruction* call, | 2276 Instruction* call, |
| 2319 Definition* receiver, | 2277 Definition* receiver, |
| 2320 TokenPosition token_pos, | 2278 TokenPosition token_pos, |
| 2321 const Cids* value_check, | 2279 const Cids* value_check, |
| 2322 TargetEntryInstr** entry, | 2280 TargetEntryInstr** entry, |
| 2323 Definition** last) { | 2281 Definition** last) { |
| 2324 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); | 2282 intptr_t array_cid = MethodRecognizer::MethodKindToReceiverCid(kind); |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2445 | 2403 |
| 2446 const intptr_t index_scale = Instance::ElementSizeFor(array_cid); | 2404 const intptr_t index_scale = Instance::ElementSizeFor(array_cid); |
| 2447 *last = new (Z) StoreIndexedInstr( | 2405 *last = new (Z) StoreIndexedInstr( |
| 2448 new (Z) Value(array), new (Z) Value(index), new (Z) Value(stored_value), | 2406 new (Z) Value(array), new (Z) Value(index), new (Z) Value(stored_value), |
| 2449 needs_store_barrier, index_scale, array_cid, kAlignedAccess, | 2407 needs_store_barrier, index_scale, array_cid, kAlignedAccess, |
| 2450 call->deopt_id(), call->token_pos()); | 2408 call->deopt_id(), call->token_pos()); |
| 2451 flow_graph->AppendTo(cursor, *last, call->env(), FlowGraph::kEffect); | 2409 flow_graph->AppendTo(cursor, *last, call->env(), FlowGraph::kEffect); |
| 2452 return true; | 2410 return true; |
| 2453 } | 2411 } |
| 2454 | 2412 |
| 2455 | |
| 2456 static bool InlineDoubleOp(FlowGraph* flow_graph, | 2413 static bool InlineDoubleOp(FlowGraph* flow_graph, |
| 2457 Token::Kind op_kind, | 2414 Token::Kind op_kind, |
| 2458 Instruction* call, | 2415 Instruction* call, |
| 2459 Definition* receiver, | 2416 Definition* receiver, |
| 2460 TargetEntryInstr** entry, | 2417 TargetEntryInstr** entry, |
| 2461 Definition** last) { | 2418 Definition** last) { |
| 2462 if (!CanUnboxDouble()) { | 2419 if (!CanUnboxDouble()) { |
| 2463 return false; | 2420 return false; |
| 2464 } | 2421 } |
| 2465 Definition* left = receiver; | 2422 Definition* left = receiver; |
| 2466 Definition* right = call->ArgumentAt(1); | 2423 Definition* right = call->ArgumentAt(1); |
| 2467 | 2424 |
| 2468 *entry = new (Z) | 2425 *entry = new (Z) |
| 2469 TargetEntryInstr(flow_graph->allocate_block_id(), | 2426 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2470 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2427 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2471 (*entry)->InheritDeoptTarget(Z, call); | 2428 (*entry)->InheritDeoptTarget(Z, call); |
| 2472 // Arguments are checked. No need for class check. | 2429 // Arguments are checked. No need for class check. |
| 2473 BinaryDoubleOpInstr* double_bin_op = new (Z) | 2430 BinaryDoubleOpInstr* double_bin_op = new (Z) |
| 2474 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), | 2431 BinaryDoubleOpInstr(op_kind, new (Z) Value(left), new (Z) Value(right), |
| 2475 call->deopt_id(), call->token_pos()); | 2432 call->deopt_id(), call->token_pos()); |
| 2476 flow_graph->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue); | 2433 flow_graph->AppendTo(*entry, double_bin_op, call->env(), FlowGraph::kValue); |
| 2477 *last = double_bin_op; | 2434 *last = double_bin_op; |
| 2478 | 2435 |
| 2479 return true; | 2436 return true; |
| 2480 } | 2437 } |
| 2481 | 2438 |
| 2482 | |
| 2483 static bool InlineDoubleTestOp(FlowGraph* flow_graph, | 2439 static bool InlineDoubleTestOp(FlowGraph* flow_graph, |
| 2484 Instruction* call, | 2440 Instruction* call, |
| 2485 Definition* receiver, | 2441 Definition* receiver, |
| 2486 MethodRecognizer::Kind kind, | 2442 MethodRecognizer::Kind kind, |
| 2487 TargetEntryInstr** entry, | 2443 TargetEntryInstr** entry, |
| 2488 Definition** last) { | 2444 Definition** last) { |
| 2489 if (!CanUnboxDouble()) { | 2445 if (!CanUnboxDouble()) { |
| 2490 return false; | 2446 return false; |
| 2491 } | 2447 } |
| 2492 | 2448 |
| 2493 *entry = new (Z) | 2449 *entry = new (Z) |
| 2494 TargetEntryInstr(flow_graph->allocate_block_id(), | 2450 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2495 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2451 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2496 (*entry)->InheritDeoptTarget(Z, call); | 2452 (*entry)->InheritDeoptTarget(Z, call); |
| 2497 // Arguments are checked. No need for class check. | 2453 // Arguments are checked. No need for class check. |
| 2498 | 2454 |
| 2499 DoubleTestOpInstr* double_test_op = new (Z) DoubleTestOpInstr( | 2455 DoubleTestOpInstr* double_test_op = new (Z) DoubleTestOpInstr( |
| 2500 kind, new (Z) Value(receiver), call->deopt_id(), call->token_pos()); | 2456 kind, new (Z) Value(receiver), call->deopt_id(), call->token_pos()); |
| 2501 flow_graph->AppendTo(*entry, double_test_op, call->env(), FlowGraph::kValue); | 2457 flow_graph->AppendTo(*entry, double_test_op, call->env(), FlowGraph::kValue); |
| 2502 *last = double_test_op; | 2458 *last = double_test_op; |
| 2503 | 2459 |
| 2504 return true; | 2460 return true; |
| 2505 } | 2461 } |
| 2506 | 2462 |
| 2507 | |
| 2508 static bool InlineSmiBitAndFromSmi(FlowGraph* flow_graph, | 2463 static bool InlineSmiBitAndFromSmi(FlowGraph* flow_graph, |
| 2509 Instruction* call, | 2464 Instruction* call, |
| 2510 Definition* receiver, | 2465 Definition* receiver, |
| 2511 TargetEntryInstr** entry, | 2466 TargetEntryInstr** entry, |
| 2512 Definition** last) { | 2467 Definition** last) { |
| 2513 Definition* left = receiver; | 2468 Definition* left = receiver; |
| 2514 Definition* right = call->ArgumentAt(1); | 2469 Definition* right = call->ArgumentAt(1); |
| 2515 | 2470 |
| 2516 *entry = new (Z) | 2471 *entry = new (Z) |
| 2517 TargetEntryInstr(flow_graph->allocate_block_id(), | 2472 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2518 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2473 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2519 (*entry)->InheritDeoptTarget(Z, call); | 2474 (*entry)->InheritDeoptTarget(Z, call); |
| 2520 // Right arguments is known to be smi: other._bitAndFromSmi(this); | 2475 // Right arguments is known to be smi: other._bitAndFromSmi(this); |
| 2521 BinarySmiOpInstr* smi_op = | 2476 BinarySmiOpInstr* smi_op = |
| 2522 new (Z) BinarySmiOpInstr(Token::kBIT_AND, new (Z) Value(left), | 2477 new (Z) BinarySmiOpInstr(Token::kBIT_AND, new (Z) Value(left), |
| 2523 new (Z) Value(right), call->deopt_id()); | 2478 new (Z) Value(right), call->deopt_id()); |
| 2524 flow_graph->AppendTo(*entry, smi_op, call->env(), FlowGraph::kValue); | 2479 flow_graph->AppendTo(*entry, smi_op, call->env(), FlowGraph::kValue); |
| 2525 *last = smi_op; | 2480 *last = smi_op; |
| 2526 | 2481 |
| 2527 return true; | 2482 return true; |
| 2528 } | 2483 } |
| 2529 | 2484 |
| 2530 | |
| 2531 static bool InlineGrowableArraySetter(FlowGraph* flow_graph, | 2485 static bool InlineGrowableArraySetter(FlowGraph* flow_graph, |
| 2532 intptr_t offset, | 2486 intptr_t offset, |
| 2533 StoreBarrierType store_barrier_type, | 2487 StoreBarrierType store_barrier_type, |
| 2534 Instruction* call, | 2488 Instruction* call, |
| 2535 Definition* receiver, | 2489 Definition* receiver, |
| 2536 TargetEntryInstr** entry, | 2490 TargetEntryInstr** entry, |
| 2537 Definition** last) { | 2491 Definition** last) { |
| 2538 Definition* array = receiver; | 2492 Definition* array = receiver; |
| 2539 Definition* value = call->ArgumentAt(1); | 2493 Definition* value = call->ArgumentAt(1); |
| 2540 | 2494 |
| 2541 *entry = new (Z) | 2495 *entry = new (Z) |
| 2542 TargetEntryInstr(flow_graph->allocate_block_id(), | 2496 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2543 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2497 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2544 (*entry)->InheritDeoptTarget(Z, call); | 2498 (*entry)->InheritDeoptTarget(Z, call); |
| 2545 | 2499 |
| 2546 // This is an internal method, no need to check argument types. | 2500 // This is an internal method, no need to check argument types. |
| 2547 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr( | 2501 StoreInstanceFieldInstr* store = new (Z) StoreInstanceFieldInstr( |
| 2548 offset, new (Z) Value(array), new (Z) Value(value), store_barrier_type, | 2502 offset, new (Z) Value(array), new (Z) Value(value), store_barrier_type, |
| 2549 call->token_pos()); | 2503 call->token_pos()); |
| 2550 flow_graph->AppendTo(*entry, store, call->env(), FlowGraph::kEffect); | 2504 flow_graph->AppendTo(*entry, store, call->env(), FlowGraph::kEffect); |
| 2551 *last = store; | 2505 *last = store; |
| 2552 | 2506 |
| 2553 return true; | 2507 return true; |
| 2554 } | 2508 } |
| 2555 | 2509 |
| 2556 | |
| 2557 static void PrepareInlineByteArrayBaseOp(FlowGraph* flow_graph, | 2510 static void PrepareInlineByteArrayBaseOp(FlowGraph* flow_graph, |
| 2558 Instruction* call, | 2511 Instruction* call, |
| 2559 intptr_t array_cid, | 2512 intptr_t array_cid, |
| 2560 intptr_t view_cid, | 2513 intptr_t view_cid, |
| 2561 Definition** array, | 2514 Definition** array, |
| 2562 Definition* byte_index, | 2515 Definition* byte_index, |
| 2563 Instruction** cursor) { | 2516 Instruction** cursor) { |
| 2564 LoadFieldInstr* length = new (Z) LoadFieldInstr( | 2517 LoadFieldInstr* length = new (Z) LoadFieldInstr( |
| 2565 new (Z) Value(*array), CheckArrayBoundInstr::LengthOffsetFor(array_cid), | 2518 new (Z) Value(*array), CheckArrayBoundInstr::LengthOffsetFor(array_cid), |
| 2566 Type::ZoneHandle(Z, Type::SmiType()), call->token_pos()); | 2519 Type::ZoneHandle(Z, Type::SmiType()), call->token_pos()); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2607 call->env(), FlowGraph::kEffect); | 2560 call->env(), FlowGraph::kEffect); |
| 2608 | 2561 |
| 2609 if (RawObject::IsExternalTypedDataClassId(array_cid)) { | 2562 if (RawObject::IsExternalTypedDataClassId(array_cid)) { |
| 2610 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( | 2563 LoadUntaggedInstr* elements = new (Z) LoadUntaggedInstr( |
| 2611 new (Z) Value(*array), ExternalTypedData::data_offset()); | 2564 new (Z) Value(*array), ExternalTypedData::data_offset()); |
| 2612 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); | 2565 *cursor = flow_graph->AppendTo(*cursor, elements, NULL, FlowGraph::kValue); |
| 2613 *array = elements; | 2566 *array = elements; |
| 2614 } | 2567 } |
| 2615 } | 2568 } |
| 2616 | 2569 |
| 2617 | |
| 2618 static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph, | 2570 static bool InlineByteArrayBaseLoad(FlowGraph* flow_graph, |
| 2619 Instruction* call, | 2571 Instruction* call, |
| 2620 Definition* receiver, | 2572 Definition* receiver, |
| 2621 intptr_t array_cid, | 2573 intptr_t array_cid, |
| 2622 intptr_t view_cid, | 2574 intptr_t view_cid, |
| 2623 TargetEntryInstr** entry, | 2575 TargetEntryInstr** entry, |
| 2624 Definition** last) { | 2576 Definition** last) { |
| 2625 ASSERT(array_cid != kIllegalCid); | 2577 ASSERT(array_cid != kIllegalCid); |
| 2626 Definition* array = receiver; | 2578 Definition* array = receiver; |
| 2627 Definition* index = call->ArgumentAt(1); | 2579 Definition* index = call->ArgumentAt(1); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 2650 | 2602 |
| 2651 if (view_cid == kTypedDataFloat32ArrayCid) { | 2603 if (view_cid == kTypedDataFloat32ArrayCid) { |
| 2652 *last = new (Z) FloatToDoubleInstr(new (Z) Value(*last), deopt_id); | 2604 *last = new (Z) FloatToDoubleInstr(new (Z) Value(*last), deopt_id); |
| 2653 flow_graph->AppendTo(cursor, *last, | 2605 flow_graph->AppendTo(cursor, *last, |
| 2654 deopt_id != Thread::kNoDeoptId ? call->env() : NULL, | 2606 deopt_id != Thread::kNoDeoptId ? call->env() : NULL, |
| 2655 FlowGraph::kValue); | 2607 FlowGraph::kValue); |
| 2656 } | 2608 } |
| 2657 return true; | 2609 return true; |
| 2658 } | 2610 } |
| 2659 | 2611 |
| 2660 | |
| 2661 static bool InlineByteArrayBaseStore(FlowGraph* flow_graph, | 2612 static bool InlineByteArrayBaseStore(FlowGraph* flow_graph, |
| 2662 const Function& target, | 2613 const Function& target, |
| 2663 Instruction* call, | 2614 Instruction* call, |
| 2664 Definition* receiver, | 2615 Definition* receiver, |
| 2665 intptr_t array_cid, | 2616 intptr_t array_cid, |
| 2666 intptr_t view_cid, | 2617 intptr_t view_cid, |
| 2667 TargetEntryInstr** entry, | 2618 TargetEntryInstr** entry, |
| 2668 Definition** last) { | 2619 Definition** last) { |
| 2669 ASSERT(array_cid != kIllegalCid); | 2620 ASSERT(array_cid != kIllegalCid); |
| 2670 Definition* array = receiver; | 2621 Definition* array = receiver; |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2763 1, // Index scale | 2714 1, // Index scale |
| 2764 view_cid, kUnalignedAccess, call->deopt_id(), call->token_pos()); | 2715 view_cid, kUnalignedAccess, call->deopt_id(), call->token_pos()); |
| 2765 | 2716 |
| 2766 flow_graph->AppendTo( | 2717 flow_graph->AppendTo( |
| 2767 cursor, *last, | 2718 cursor, *last, |
| 2768 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 2719 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 2769 FlowGraph::kEffect); | 2720 FlowGraph::kEffect); |
| 2770 return true; | 2721 return true; |
| 2771 } | 2722 } |
| 2772 | 2723 |
| 2773 | |
| 2774 // Returns the LoadIndexedInstr. | 2724 // Returns the LoadIndexedInstr. |
| 2775 static Definition* PrepareInlineStringIndexOp(FlowGraph* flow_graph, | 2725 static Definition* PrepareInlineStringIndexOp(FlowGraph* flow_graph, |
| 2776 Instruction* call, | 2726 Instruction* call, |
| 2777 intptr_t cid, | 2727 intptr_t cid, |
| 2778 Definition* str, | 2728 Definition* str, |
| 2779 Definition* index, | 2729 Definition* index, |
| 2780 Instruction* cursor) { | 2730 Instruction* cursor) { |
| 2781 // Load the length of the string. | 2731 // Load the length of the string. |
| 2782 // Treat length loads as mutable (i.e. affected by side effects) to avoid | 2732 // Treat length loads as mutable (i.e. affected by side effects) to avoid |
| 2783 // hoisting them since we can't hoist the preceding class-check. This | 2733 // hoisting them since we can't hoist the preceding class-check. This |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2816 | 2766 |
| 2817 LoadIndexedInstr* load_indexed = new (Z) LoadIndexedInstr( | 2767 LoadIndexedInstr* load_indexed = new (Z) LoadIndexedInstr( |
| 2818 new (Z) Value(str), new (Z) Value(index), Instance::ElementSizeFor(cid), | 2768 new (Z) Value(str), new (Z) Value(index), Instance::ElementSizeFor(cid), |
| 2819 cid, kAlignedAccess, Thread::kNoDeoptId, call->token_pos()); | 2769 cid, kAlignedAccess, Thread::kNoDeoptId, call->token_pos()); |
| 2820 | 2770 |
| 2821 cursor = flow_graph->AppendTo(cursor, load_indexed, NULL, FlowGraph::kValue); | 2771 cursor = flow_graph->AppendTo(cursor, load_indexed, NULL, FlowGraph::kValue); |
| 2822 ASSERT(cursor == load_indexed); | 2772 ASSERT(cursor == load_indexed); |
| 2823 return load_indexed; | 2773 return load_indexed; |
| 2824 } | 2774 } |
| 2825 | 2775 |
| 2826 | |
| 2827 static bool InlineStringBaseCharAt(FlowGraph* flow_graph, | 2776 static bool InlineStringBaseCharAt(FlowGraph* flow_graph, |
| 2828 Instruction* call, | 2777 Instruction* call, |
| 2829 Definition* receiver, | 2778 Definition* receiver, |
| 2830 intptr_t cid, | 2779 intptr_t cid, |
| 2831 TargetEntryInstr** entry, | 2780 TargetEntryInstr** entry, |
| 2832 Definition** last) { | 2781 Definition** last) { |
| 2833 if ((cid != kOneByteStringCid) && (cid != kExternalOneByteStringCid)) { | 2782 if ((cid != kOneByteStringCid) && (cid != kExternalOneByteStringCid)) { |
| 2834 return false; | 2783 return false; |
| 2835 } | 2784 } |
| 2836 Definition* str = receiver; | 2785 Definition* str = receiver; |
| 2837 Definition* index = call->ArgumentAt(1); | 2786 Definition* index = call->ArgumentAt(1); |
| 2838 | 2787 |
| 2839 *entry = new (Z) | 2788 *entry = new (Z) |
| 2840 TargetEntryInstr(flow_graph->allocate_block_id(), | 2789 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2841 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2790 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2842 (*entry)->InheritDeoptTarget(Z, call); | 2791 (*entry)->InheritDeoptTarget(Z, call); |
| 2843 | 2792 |
| 2844 *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); | 2793 *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); |
| 2845 | 2794 |
| 2846 OneByteStringFromCharCodeInstr* char_at = | 2795 OneByteStringFromCharCodeInstr* char_at = |
| 2847 new (Z) OneByteStringFromCharCodeInstr(new (Z) Value(*last)); | 2796 new (Z) OneByteStringFromCharCodeInstr(new (Z) Value(*last)); |
| 2848 | 2797 |
| 2849 flow_graph->AppendTo(*last, char_at, NULL, FlowGraph::kValue); | 2798 flow_graph->AppendTo(*last, char_at, NULL, FlowGraph::kValue); |
| 2850 *last = char_at; | 2799 *last = char_at; |
| 2851 | 2800 |
| 2852 return true; | 2801 return true; |
| 2853 } | 2802 } |
| 2854 | 2803 |
| 2855 | |
| 2856 static bool InlineStringCodeUnitAt(FlowGraph* flow_graph, | 2804 static bool InlineStringCodeUnitAt(FlowGraph* flow_graph, |
| 2857 Instruction* call, | 2805 Instruction* call, |
| 2858 Definition* receiver, | 2806 Definition* receiver, |
| 2859 intptr_t cid, | 2807 intptr_t cid, |
| 2860 TargetEntryInstr** entry, | 2808 TargetEntryInstr** entry, |
| 2861 Definition** last) { | 2809 Definition** last) { |
| 2862 ASSERT((cid == kOneByteStringCid) || (cid == kTwoByteStringCid) || | 2810 ASSERT((cid == kOneByteStringCid) || (cid == kTwoByteStringCid) || |
| 2863 (cid == kExternalOneByteStringCid) || | 2811 (cid == kExternalOneByteStringCid) || |
| 2864 (cid == kExternalTwoByteStringCid)); | 2812 (cid == kExternalTwoByteStringCid)); |
| 2865 Definition* str = receiver; | 2813 Definition* str = receiver; |
| 2866 Definition* index = call->ArgumentAt(1); | 2814 Definition* index = call->ArgumentAt(1); |
| 2867 | 2815 |
| 2868 *entry = new (Z) | 2816 *entry = new (Z) |
| 2869 TargetEntryInstr(flow_graph->allocate_block_id(), | 2817 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 2870 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 2818 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 2871 (*entry)->InheritDeoptTarget(Z, call); | 2819 (*entry)->InheritDeoptTarget(Z, call); |
| 2872 | 2820 |
| 2873 *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); | 2821 *last = PrepareInlineStringIndexOp(flow_graph, call, cid, str, index, *entry); |
| 2874 | 2822 |
| 2875 return true; | 2823 return true; |
| 2876 } | 2824 } |
| 2877 | 2825 |
| 2878 | |
| 2879 // Only used for monomorphic calls. | 2826 // Only used for monomorphic calls. |
| 2880 bool FlowGraphInliner::TryReplaceInstanceCallWithInline( | 2827 bool FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 2881 FlowGraph* flow_graph, | 2828 FlowGraph* flow_graph, |
| 2882 ForwardInstructionIterator* iterator, | 2829 ForwardInstructionIterator* iterator, |
| 2883 InstanceCallInstr* call) { | 2830 InstanceCallInstr* call) { |
| 2884 Function& target = Function::Handle(Z); | 2831 Function& target = Function::Handle(Z); |
| 2885 GrowableArray<intptr_t> class_ids; | 2832 GrowableArray<intptr_t> class_ids; |
| 2886 call->ic_data()->GetCheckAt(0, &class_ids, &target); | 2833 call->ic_data()->GetCheckAt(0, &class_ids, &target); |
| 2887 const intptr_t receiver_cid = class_ids[0]; | 2834 const intptr_t receiver_cid = class_ids[0]; |
| 2888 | 2835 |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2922 // Remove through the iterator. | 2869 // Remove through the iterator. |
| 2923 ASSERT(iterator->Current() == call); | 2870 ASSERT(iterator->Current() == call); |
| 2924 iterator->RemoveCurrentFromGraph(); | 2871 iterator->RemoveCurrentFromGraph(); |
| 2925 call->set_previous(NULL); | 2872 call->set_previous(NULL); |
| 2926 call->set_next(NULL); | 2873 call->set_next(NULL); |
| 2927 return true; | 2874 return true; |
| 2928 } | 2875 } |
| 2929 return false; | 2876 return false; |
| 2930 } | 2877 } |
| 2931 | 2878 |
| 2932 | |
| 2933 bool FlowGraphInliner::TryReplaceStaticCallWithInline( | 2879 bool FlowGraphInliner::TryReplaceStaticCallWithInline( |
| 2934 FlowGraph* flow_graph, | 2880 FlowGraph* flow_graph, |
| 2935 ForwardInstructionIterator* iterator, | 2881 ForwardInstructionIterator* iterator, |
| 2936 StaticCallInstr* call) { | 2882 StaticCallInstr* call) { |
| 2937 TargetEntryInstr* entry; | 2883 TargetEntryInstr* entry; |
| 2938 Definition* last; | 2884 Definition* last; |
| 2939 if (FlowGraphInliner::TryInlineRecognizedMethod( | 2885 if (FlowGraphInliner::TryInlineRecognizedMethod( |
| 2940 flow_graph, kIllegalCid, call->function(), call, NULL, | 2886 flow_graph, kIllegalCid, call->function(), call, NULL, |
| 2941 call->token_pos(), *call->ic_data(), &entry, &last)) { | 2887 call->token_pos(), *call->ic_data(), &entry, &last)) { |
| 2942 // Remove the original push arguments. | 2888 // Remove the original push arguments. |
| (...skipping 18 matching lines...) Expand all Loading... |
| 2961 // Remove through the iterator. | 2907 // Remove through the iterator. |
| 2962 ASSERT(iterator->Current() == call); | 2908 ASSERT(iterator->Current() == call); |
| 2963 iterator->RemoveCurrentFromGraph(); | 2909 iterator->RemoveCurrentFromGraph(); |
| 2964 call->set_previous(NULL); | 2910 call->set_previous(NULL); |
| 2965 call->set_next(NULL); | 2911 call->set_next(NULL); |
| 2966 return true; | 2912 return true; |
| 2967 } | 2913 } |
| 2968 return false; | 2914 return false; |
| 2969 } | 2915 } |
| 2970 | 2916 |
| 2971 | |
| 2972 static bool InlineFloat32x4Method(FlowGraph* flow_graph, | 2917 static bool InlineFloat32x4Method(FlowGraph* flow_graph, |
| 2973 Instruction* call, | 2918 Instruction* call, |
| 2974 Definition* receiver, | 2919 Definition* receiver, |
| 2975 MethodRecognizer::Kind kind, | 2920 MethodRecognizer::Kind kind, |
| 2976 TargetEntryInstr** entry, | 2921 TargetEntryInstr** entry, |
| 2977 Definition** last) { | 2922 Definition** last) { |
| 2978 if (!ShouldInlineSimd()) { | 2923 if (!ShouldInlineSimd()) { |
| 2979 return false; | 2924 return false; |
| 2980 } | 2925 } |
| 2981 | 2926 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3067 UNREACHABLE(); | 3012 UNREACHABLE(); |
| 3068 return false; | 3013 return false; |
| 3069 } | 3014 } |
| 3070 flow_graph->AppendTo( | 3015 flow_graph->AppendTo( |
| 3071 cursor, *last, | 3016 cursor, *last, |
| 3072 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3017 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3073 FlowGraph::kValue); | 3018 FlowGraph::kValue); |
| 3074 return true; | 3019 return true; |
| 3075 } | 3020 } |
| 3076 | 3021 |
| 3077 | |
| 3078 static bool CheckMask(Definition* definition, intptr_t* mask_ptr) { | 3022 static bool CheckMask(Definition* definition, intptr_t* mask_ptr) { |
| 3079 if (!definition->IsConstant()) return false; | 3023 if (!definition->IsConstant()) return false; |
| 3080 ConstantInstr* constant_instruction = definition->AsConstant(); | 3024 ConstantInstr* constant_instruction = definition->AsConstant(); |
| 3081 const Object& constant_mask = constant_instruction->value(); | 3025 const Object& constant_mask = constant_instruction->value(); |
| 3082 if (!constant_mask.IsSmi()) return false; | 3026 if (!constant_mask.IsSmi()) return false; |
| 3083 const intptr_t mask = Smi::Cast(constant_mask).Value(); | 3027 const intptr_t mask = Smi::Cast(constant_mask).Value(); |
| 3084 if ((mask < 0) || (mask > 255)) { | 3028 if ((mask < 0) || (mask > 255)) { |
| 3085 return false; // Not a valid mask. | 3029 return false; // Not a valid mask. |
| 3086 } | 3030 } |
| 3087 *mask_ptr = mask; | 3031 *mask_ptr = mask; |
| 3088 return true; | 3032 return true; |
| 3089 } | 3033 } |
| 3090 | 3034 |
| 3091 | |
| 3092 static bool InlineSimdShuffleMethod(FlowGraph* flow_graph, | 3035 static bool InlineSimdShuffleMethod(FlowGraph* flow_graph, |
| 3093 Instruction* call, | 3036 Instruction* call, |
| 3094 Definition* receiver, | 3037 Definition* receiver, |
| 3095 MethodRecognizer::Kind kind, | 3038 MethodRecognizer::Kind kind, |
| 3096 TargetEntryInstr** entry, | 3039 TargetEntryInstr** entry, |
| 3097 Definition** last) { | 3040 Definition** last) { |
| 3098 if (!ShouldInlineSimd()) { | 3041 if (!ShouldInlineSimd()) { |
| 3099 return false; | 3042 return false; |
| 3100 } | 3043 } |
| 3101 *entry = new (Z) | 3044 *entry = new (Z) |
| 3102 TargetEntryInstr(flow_graph->allocate_block_id(), | 3045 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3103 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 3046 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 3104 (*entry)->InheritDeoptTarget(Z, call); | 3047 (*entry)->InheritDeoptTarget(Z, call); |
| 3105 Instruction* cursor = *entry; | 3048 Instruction* cursor = *entry; |
| 3106 Definition* mask_definition = call->ArgumentAt(1); | 3049 Definition* mask_definition = call->ArgumentAt(1); |
| 3107 intptr_t mask = 0; | 3050 intptr_t mask = 0; |
| 3108 if (!CheckMask(mask_definition, &mask)) { | 3051 if (!CheckMask(mask_definition, &mask)) { |
| 3109 return false; | 3052 return false; |
| 3110 } | 3053 } |
| 3111 *last = new (Z) Simd32x4ShuffleInstr(kind, new (Z) Value(call->ArgumentAt(0)), | 3054 *last = new (Z) Simd32x4ShuffleInstr(kind, new (Z) Value(call->ArgumentAt(0)), |
| 3112 mask, call->deopt_id()); | 3055 mask, call->deopt_id()); |
| 3113 flow_graph->AppendTo( | 3056 flow_graph->AppendTo( |
| 3114 cursor, *last, | 3057 cursor, *last, |
| 3115 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3058 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3116 FlowGraph::kValue); | 3059 FlowGraph::kValue); |
| 3117 return true; | 3060 return true; |
| 3118 } | 3061 } |
| 3119 | 3062 |
| 3120 | |
| 3121 static bool InlineSimdShuffleMixMethod(FlowGraph* flow_graph, | 3063 static bool InlineSimdShuffleMixMethod(FlowGraph* flow_graph, |
| 3122 Instruction* call, | 3064 Instruction* call, |
| 3123 Definition* receiver, | 3065 Definition* receiver, |
| 3124 MethodRecognizer::Kind kind, | 3066 MethodRecognizer::Kind kind, |
| 3125 TargetEntryInstr** entry, | 3067 TargetEntryInstr** entry, |
| 3126 Definition** last) { | 3068 Definition** last) { |
| 3127 if (!ShouldInlineSimd()) { | 3069 if (!ShouldInlineSimd()) { |
| 3128 return false; | 3070 return false; |
| 3129 } | 3071 } |
| 3130 *entry = new (Z) | 3072 *entry = new (Z) |
| 3131 TargetEntryInstr(flow_graph->allocate_block_id(), | 3073 TargetEntryInstr(flow_graph->allocate_block_id(), |
| 3132 call->GetBlock()->try_index(), Thread::kNoDeoptId); | 3074 call->GetBlock()->try_index(), Thread::kNoDeoptId); |
| 3133 (*entry)->InheritDeoptTarget(Z, call); | 3075 (*entry)->InheritDeoptTarget(Z, call); |
| 3134 Instruction* cursor = *entry; | 3076 Instruction* cursor = *entry; |
| 3135 Definition* mask_definition = call->ArgumentAt(2); | 3077 Definition* mask_definition = call->ArgumentAt(2); |
| 3136 intptr_t mask = 0; | 3078 intptr_t mask = 0; |
| 3137 if (!CheckMask(mask_definition, &mask)) { | 3079 if (!CheckMask(mask_definition, &mask)) { |
| 3138 return false; | 3080 return false; |
| 3139 } | 3081 } |
| 3140 *last = new (Z) Simd32x4ShuffleMixInstr(kind, new (Z) Value(receiver), | 3082 *last = new (Z) Simd32x4ShuffleMixInstr(kind, new (Z) Value(receiver), |
| 3141 new (Z) Value(call->ArgumentAt(1)), | 3083 new (Z) Value(call->ArgumentAt(1)), |
| 3142 mask, call->deopt_id()); | 3084 mask, call->deopt_id()); |
| 3143 flow_graph->AppendTo( | 3085 flow_graph->AppendTo( |
| 3144 cursor, *last, | 3086 cursor, *last, |
| 3145 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3087 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3146 FlowGraph::kValue); | 3088 FlowGraph::kValue); |
| 3147 return true; | 3089 return true; |
| 3148 } | 3090 } |
| 3149 | 3091 |
| 3150 | |
| 3151 static bool InlineInt32x4Method(FlowGraph* flow_graph, | 3092 static bool InlineInt32x4Method(FlowGraph* flow_graph, |
| 3152 Instruction* call, | 3093 Instruction* call, |
| 3153 Definition* receiver, | 3094 Definition* receiver, |
| 3154 MethodRecognizer::Kind kind, | 3095 MethodRecognizer::Kind kind, |
| 3155 TargetEntryInstr** entry, | 3096 TargetEntryInstr** entry, |
| 3156 Definition** last) { | 3097 Definition** last) { |
| 3157 if (!ShouldInlineSimd()) { | 3098 if (!ShouldInlineSimd()) { |
| 3158 return false; | 3099 return false; |
| 3159 } | 3100 } |
| 3160 *entry = new (Z) | 3101 *entry = new (Z) |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3197 default: | 3138 default: |
| 3198 return false; | 3139 return false; |
| 3199 } | 3140 } |
| 3200 flow_graph->AppendTo( | 3141 flow_graph->AppendTo( |
| 3201 cursor, *last, | 3142 cursor, *last, |
| 3202 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3143 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3203 FlowGraph::kValue); | 3144 FlowGraph::kValue); |
| 3204 return true; | 3145 return true; |
| 3205 } | 3146 } |
| 3206 | 3147 |
| 3207 | |
| 3208 static bool InlineFloat64x2Method(FlowGraph* flow_graph, | 3148 static bool InlineFloat64x2Method(FlowGraph* flow_graph, |
| 3209 Instruction* call, | 3149 Instruction* call, |
| 3210 Definition* receiver, | 3150 Definition* receiver, |
| 3211 MethodRecognizer::Kind kind, | 3151 MethodRecognizer::Kind kind, |
| 3212 TargetEntryInstr** entry, | 3152 TargetEntryInstr** entry, |
| 3213 Definition** last) { | 3153 Definition** last) { |
| 3214 if (!ShouldInlineSimd()) { | 3154 if (!ShouldInlineSimd()) { |
| 3215 return false; | 3155 return false; |
| 3216 } | 3156 } |
| 3217 *entry = new (Z) | 3157 *entry = new (Z) |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3250 UNREACHABLE(); | 3190 UNREACHABLE(); |
| 3251 return false; | 3191 return false; |
| 3252 } | 3192 } |
| 3253 flow_graph->AppendTo( | 3193 flow_graph->AppendTo( |
| 3254 cursor, *last, | 3194 cursor, *last, |
| 3255 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3195 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3256 FlowGraph::kValue); | 3196 FlowGraph::kValue); |
| 3257 return true; | 3197 return true; |
| 3258 } | 3198 } |
| 3259 | 3199 |
| 3260 | |
| 3261 static bool InlineSimdConstructor(FlowGraph* flow_graph, | 3200 static bool InlineSimdConstructor(FlowGraph* flow_graph, |
| 3262 Instruction* call, | 3201 Instruction* call, |
| 3263 MethodRecognizer::Kind kind, | 3202 MethodRecognizer::Kind kind, |
| 3264 TargetEntryInstr** entry, | 3203 TargetEntryInstr** entry, |
| 3265 Definition** last) { | 3204 Definition** last) { |
| 3266 if (!ShouldInlineSimd()) { | 3205 if (!ShouldInlineSimd()) { |
| 3267 return false; | 3206 return false; |
| 3268 } | 3207 } |
| 3269 *entry = new (Z) | 3208 *entry = new (Z) |
| 3270 TargetEntryInstr(flow_graph->allocate_block_id(), | 3209 TargetEntryInstr(flow_graph->allocate_block_id(), |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3332 UNREACHABLE(); | 3271 UNREACHABLE(); |
| 3333 return false; | 3272 return false; |
| 3334 } | 3273 } |
| 3335 flow_graph->AppendTo( | 3274 flow_graph->AppendTo( |
| 3336 cursor, *last, | 3275 cursor, *last, |
| 3337 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3276 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3338 FlowGraph::kValue); | 3277 FlowGraph::kValue); |
| 3339 return true; | 3278 return true; |
| 3340 } | 3279 } |
| 3341 | 3280 |
| 3342 | |
| 3343 static bool InlineMathCFunction(FlowGraph* flow_graph, | 3281 static bool InlineMathCFunction(FlowGraph* flow_graph, |
| 3344 Instruction* call, | 3282 Instruction* call, |
| 3345 MethodRecognizer::Kind kind, | 3283 MethodRecognizer::Kind kind, |
| 3346 TargetEntryInstr** entry, | 3284 TargetEntryInstr** entry, |
| 3347 Definition** last) { | 3285 Definition** last) { |
| 3348 if (!CanUnboxDouble()) { | 3286 if (!CanUnboxDouble()) { |
| 3349 return false; | 3287 return false; |
| 3350 } | 3288 } |
| 3351 *entry = new (Z) | 3289 *entry = new (Z) |
| 3352 TargetEntryInstr(flow_graph->allocate_block_id(), | 3290 TargetEntryInstr(flow_graph->allocate_block_id(), |
| (...skipping 19 matching lines...) Expand all Loading... |
| 3372 break; | 3310 break; |
| 3373 } | 3311 } |
| 3374 } | 3312 } |
| 3375 flow_graph->AppendTo( | 3313 flow_graph->AppendTo( |
| 3376 cursor, *last, | 3314 cursor, *last, |
| 3377 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3315 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3378 FlowGraph::kValue); | 3316 FlowGraph::kValue); |
| 3379 return true; | 3317 return true; |
| 3380 } | 3318 } |
| 3381 | 3319 |
| 3382 | |
| 3383 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, | 3320 bool FlowGraphInliner::TryInlineRecognizedMethod(FlowGraph* flow_graph, |
| 3384 intptr_t receiver_cid, | 3321 intptr_t receiver_cid, |
| 3385 const Function& target, | 3322 const Function& target, |
| 3386 Definition* call, | 3323 Definition* call, |
| 3387 Definition* receiver, | 3324 Definition* receiver, |
| 3388 TokenPosition token_pos, | 3325 TokenPosition token_pos, |
| 3389 const ICData& ic_data, | 3326 const ICData& ic_data, |
| 3390 TargetEntryInstr** entry, | 3327 TargetEntryInstr** entry, |
| 3391 Definition** last) { | 3328 Definition** last) { |
| 3392 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); | 3329 MethodRecognizer::Kind kind = MethodRecognizer::RecognizeKind(target); |
| (...skipping 402 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3795 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, | 3732 call->deopt_id() != Thread::kNoDeoptId ? call->env() : NULL, |
| 3796 FlowGraph::kEffect); | 3733 FlowGraph::kEffect); |
| 3797 return true; | 3734 return true; |
| 3798 } | 3735 } |
| 3799 | 3736 |
| 3800 default: | 3737 default: |
| 3801 return false; | 3738 return false; |
| 3802 } | 3739 } |
| 3803 } | 3740 } |
| 3804 | 3741 |
| 3805 | |
| 3806 } // namespace dart | 3742 } // namespace dart |
| 3807 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3743 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
| OLD | NEW |