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 |