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" | 8 #include "vm/precompiler.h" |
9 #include "vm/block_scheduler.h" | 9 #include "vm/block_scheduler.h" |
10 #include "vm/branch_optimizer.h" | 10 #include "vm/branch_optimizer.h" |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 continue; | 170 continue; |
171 } | 171 } |
172 if (current->IsPolymorphicInstanceCall()) { | 172 if (current->IsPolymorphicInstanceCall()) { |
173 PolymorphicInstanceCallInstr* call = | 173 PolymorphicInstanceCallInstr* call = |
174 current->AsPolymorphicInstanceCall(); | 174 current->AsPolymorphicInstanceCall(); |
175 // These checks make sure that the number of call-sites counted does | 175 // These checks make sure that the number of call-sites counted does |
176 // not change relative to the time when the current set of inlining | 176 // not change relative to the time when the current set of inlining |
177 // parameters was fixed. | 177 // parameters was fixed. |
178 // TODO(fschneider): Determine new heuristic parameters that avoid | 178 // TODO(fschneider): Determine new heuristic parameters that avoid |
179 // these checks entirely. | 179 // these checks entirely. |
180 if (!call->HasSingleRecognizedTarget() && | 180 if (!call->IsSureToCallSingleRecognizedTarget() && |
181 (call->instance_call()->token_kind() != Token::kEQ)) { | 181 (call->instance_call()->token_kind() != Token::kEQ)) { |
182 ++call_site_count_; | 182 ++call_site_count_; |
183 } | 183 } |
184 } | 184 } |
185 } | 185 } |
186 } | 186 } |
187 } | 187 } |
188 | 188 |
189 intptr_t call_site_count() const { return call_site_count_; } | 189 intptr_t call_site_count() const { return call_site_count_; } |
190 intptr_t instruction_count() const { return instruction_count_; } | 190 intptr_t instruction_count() const { return instruction_count_; } |
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
283 intptr_t instance_call_start_ix) { | 283 intptr_t instance_call_start_ix) { |
284 const intptr_t num_static_calls = | 284 const intptr_t num_static_calls = |
285 static_calls_.length() - static_call_start_ix; | 285 static_calls_.length() - static_call_start_ix; |
286 const intptr_t num_instance_calls = | 286 const intptr_t num_instance_calls = |
287 instance_calls_.length() - instance_call_start_ix; | 287 instance_calls_.length() - instance_call_start_ix; |
288 | 288 |
289 intptr_t max_count = 0; | 289 intptr_t max_count = 0; |
290 GrowableArray<intptr_t> instance_call_counts(num_instance_calls); | 290 GrowableArray<intptr_t> instance_call_counts(num_instance_calls); |
291 for (intptr_t i = 0; i < num_instance_calls; ++i) { | 291 for (intptr_t i = 0; i < num_instance_calls; ++i) { |
292 const intptr_t aggregate_count = | 292 const intptr_t aggregate_count = |
293 instance_calls_[i + instance_call_start_ix] | 293 instance_calls_[i + instance_call_start_ix].call->CallCount(); |
294 .call->ic_data() | |
295 .AggregateCount(); | |
296 instance_call_counts.Add(aggregate_count); | 294 instance_call_counts.Add(aggregate_count); |
297 if (aggregate_count > max_count) max_count = aggregate_count; | 295 if (aggregate_count > max_count) max_count = aggregate_count; |
298 } | 296 } |
299 | 297 |
300 GrowableArray<intptr_t> static_call_counts(num_static_calls); | 298 GrowableArray<intptr_t> static_call_counts(num_static_calls); |
301 for (intptr_t i = 0; i < num_static_calls; ++i) { | 299 for (intptr_t i = 0; i < num_static_calls; ++i) { |
302 intptr_t aggregate_count = 0; | 300 intptr_t aggregate_count = 0; |
303 if (static_calls_[i + static_call_start_ix].call->ic_data() == NULL) { | 301 if (static_calls_[i + static_call_start_ix].call->ic_data() == NULL) { |
304 aggregate_count = 0; | 302 aggregate_count = 0; |
305 } else { | 303 } else { |
(...skipping 30 matching lines...) Expand all Loading... |
336 Function& target = Function::ZoneHandle(); | 334 Function& target = Function::ZoneHandle(); |
337 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); | 335 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); |
338 block_it.Advance()) { | 336 block_it.Advance()) { |
339 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); | 337 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); |
340 it.Advance()) { | 338 it.Advance()) { |
341 Instruction* current = it.Current(); | 339 Instruction* current = it.Current(); |
342 Definition* call = NULL; | 340 Definition* call = NULL; |
343 if (current->IsPolymorphicInstanceCall()) { | 341 if (current->IsPolymorphicInstanceCall()) { |
344 PolymorphicInstanceCallInstr* instance_call = | 342 PolymorphicInstanceCallInstr* instance_call = |
345 current->AsPolymorphicInstanceCall(); | 343 current->AsPolymorphicInstanceCall(); |
346 target = instance_call->ic_data().GetTargetAt(0); | 344 target ^= instance_call->targets().FirstTarget().raw(); |
347 call = instance_call; | 345 call = instance_call; |
348 } else if (current->IsStaticCall()) { | 346 } else if (current->IsStaticCall()) { |
349 StaticCallInstr* static_call = current->AsStaticCall(); | 347 StaticCallInstr* static_call = current->AsStaticCall(); |
350 target = static_call->function().raw(); | 348 target ^= static_call->function().raw(); |
351 call = static_call; | 349 call = static_call; |
352 } else if (current->IsClosureCall()) { | 350 } else if (current->IsClosureCall()) { |
353 // TODO(srdjan): Add data for closure calls. | 351 // TODO(srdjan): Add data for closure calls. |
354 } | 352 } |
355 if (call != NULL) { | 353 if (call != NULL) { |
356 inlined_info->Add( | 354 inlined_info->Add( |
357 InlinedInfo(caller, &target, depth + 1, call, "Too deep")); | 355 InlinedInfo(caller, &target, depth + 1, call, "Too deep")); |
358 } | 356 } |
359 } | 357 } |
360 } | 358 } |
(...skipping 20 matching lines...) Expand all Loading... |
381 const intptr_t static_call_start_ix = static_calls_.length(); | 379 const intptr_t static_call_start_ix = static_calls_.length(); |
382 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); | 380 for (BlockIterator block_it = graph->postorder_iterator(); !block_it.Done(); |
383 block_it.Advance()) { | 381 block_it.Advance()) { |
384 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); | 382 for (ForwardInstructionIterator it(block_it.Current()); !it.Done(); |
385 it.Advance()) { | 383 it.Advance()) { |
386 Instruction* current = it.Current(); | 384 Instruction* current = it.Current(); |
387 if (current->IsPolymorphicInstanceCall()) { | 385 if (current->IsPolymorphicInstanceCall()) { |
388 PolymorphicInstanceCallInstr* instance_call = | 386 PolymorphicInstanceCallInstr* instance_call = |
389 current->AsPolymorphicInstanceCall(); | 387 current->AsPolymorphicInstanceCall(); |
390 if (!inline_only_recognized_methods || | 388 if (!inline_only_recognized_methods || |
391 instance_call->HasSingleRecognizedTarget() || | 389 instance_call->IsSureToCallSingleRecognizedTarget() || |
392 instance_call->ic_data() | 390 instance_call->HasOnlyDispatcherOrImplicitAccessorTargets()) { |
393 .HasOnlyDispatcherOrImplicitAccessorTargets()) { | |
394 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); | 391 instance_calls_.Add(InstanceCallInfo(instance_call, graph)); |
395 } else { | 392 } else { |
396 // Method not inlined because inlining too deep and method | 393 // Method not inlined because inlining too deep and method |
397 // not recognized. | 394 // not recognized. |
398 if (FLAG_print_inlining_tree) { | 395 if (FLAG_print_inlining_tree) { |
399 const Function* caller = &graph->function(); | 396 const Function* caller = &graph->function(); |
400 const Function* target = &Function::ZoneHandle( | 397 const Function* target = &instance_call->targets().FirstTarget(); |
401 instance_call->ic_data().GetTargetAt(0)); | |
402 inlined_info->Add(InlinedInfo(caller, target, depth + 1, | 398 inlined_info->Add(InlinedInfo(caller, target, depth + 1, |
403 instance_call, "Too deep")); | 399 instance_call, "Too deep")); |
404 } | 400 } |
405 } | 401 } |
406 } else if (current->IsStaticCall()) { | 402 } else if (current->IsStaticCall()) { |
407 StaticCallInstr* static_call = current->AsStaticCall(); | 403 StaticCallInstr* static_call = current->AsStaticCall(); |
408 if (!inline_only_recognized_methods || | 404 if (!inline_only_recognized_methods || |
409 static_call->function().IsRecognized() || | 405 static_call->function().IsRecognized() || |
410 static_call->function().IsDispatcherOrImplicitAccessor()) { | 406 static_call->function().IsDispatcherOrImplicitAccessor()) { |
411 static_calls_.Add(StaticCallInfo(static_call, graph)); | 407 static_calls_.Add(StaticCallInfo(static_call, graph)); |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 TargetEntryInstr* BuildDecisionGraph(); | 480 TargetEntryInstr* BuildDecisionGraph(); |
485 | 481 |
486 Isolate* isolate() const; | 482 Isolate* isolate() const; |
487 Zone* zone() const; | 483 Zone* zone() const; |
488 intptr_t AllocateBlockId() const; | 484 intptr_t AllocateBlockId() const; |
489 inline bool trace_inlining() const; | 485 inline bool trace_inlining() const; |
490 | 486 |
491 CallSiteInliner* const owner_; | 487 CallSiteInliner* const owner_; |
492 PolymorphicInstanceCallInstr* const call_; | 488 PolymorphicInstanceCallInstr* const call_; |
493 const intptr_t num_variants_; | 489 const intptr_t num_variants_; |
494 GrowableArray<CidRangeTarget> variants_; | 490 const CallTargets& variants_; |
495 | 491 |
496 GrowableArray<CidRangeTarget> inlined_variants_; | 492 CallTargets inlined_variants_; |
497 GrowableArray<CidRangeTarget> non_inlined_variants_; | 493 // The non_inlined_variants_ can be used in a long-lived instruction object, |
| 494 // so they are not embedded into the shorter-lived PolymorphicInliner object. |
| 495 CallTargets* non_inlined_variants_; |
498 GrowableArray<BlockEntryInstr*> inlined_entries_; | 496 GrowableArray<BlockEntryInstr*> inlined_entries_; |
499 InlineExitCollector* exit_collector_; | 497 InlineExitCollector* exit_collector_; |
500 | 498 |
501 const Function& caller_function_; | 499 const Function& caller_function_; |
502 const intptr_t caller_inlining_id_; | 500 const intptr_t caller_inlining_id_; |
503 }; | 501 }; |
504 | 502 |
505 | 503 |
506 static bool HasAnnotation(const Function& function, const char* annotation) { | 504 static bool HasAnnotation(const Function& function, const char* annotation) { |
507 const Class& owner = Class::Handle(function.Owner()); | 505 const Class& owner = Class::Handle(function.Owner()); |
(...skipping 790 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1298 continue; | 1296 continue; |
1299 } | 1297 } |
1300 const Function& cl = call_info[call_idx].caller(); | 1298 const Function& cl = call_info[call_idx].caller(); |
1301 intptr_t caller_inlining_id = | 1299 intptr_t caller_inlining_id = |
1302 call_info[call_idx].caller_graph->inlining_id(); | 1300 call_info[call_idx].caller_graph->inlining_id(); |
1303 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); | 1301 PolymorphicInliner inliner(this, call, cl, caller_inlining_id); |
1304 inliner.Inline(); | 1302 inliner.Inline(); |
1305 continue; | 1303 continue; |
1306 } | 1304 } |
1307 | 1305 |
1308 const ICData& ic_data = call->ic_data(); | 1306 const Function& target = call->targets().MostPopularTarget(); |
1309 const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0)); | |
1310 if (!inliner_->AlwaysInline(target) && | 1307 if (!inliner_->AlwaysInline(target) && |
1311 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { | 1308 (call_info[call_idx].ratio * 100) < FLAG_inlining_hotness) { |
1312 if (trace_inlining()) { | 1309 if (trace_inlining()) { |
1313 String& name = String::Handle(target.QualifiedUserVisibleName()); | 1310 String& name = String::Handle(target.QualifiedUserVisibleName()); |
1314 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", | 1311 THR_Print(" => %s (deopt count %d)\n Bailout: cold %f\n", |
1315 name.ToCString(), target.deoptimization_counter(), | 1312 name.ToCString(), target.deoptimization_counter(), |
1316 call_info[call_idx].ratio); | 1313 call_info[call_idx].ratio); |
1317 } | 1314 } |
1318 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target, | 1315 PRINT_INLINING_TREE("Too cold", &call_info[call_idx].caller(), &target, |
1319 call); | 1316 call); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1440 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); | 1437 DISALLOW_COPY_AND_ASSIGN(CallSiteInliner); |
1441 }; | 1438 }; |
1442 | 1439 |
1443 | 1440 |
1444 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, | 1441 PolymorphicInliner::PolymorphicInliner(CallSiteInliner* owner, |
1445 PolymorphicInstanceCallInstr* call, | 1442 PolymorphicInstanceCallInstr* call, |
1446 const Function& caller_function, | 1443 const Function& caller_function, |
1447 intptr_t caller_inlining_id) | 1444 intptr_t caller_inlining_id) |
1448 : owner_(owner), | 1445 : owner_(owner), |
1449 call_(call), | 1446 call_(call), |
1450 num_variants_(call->ic_data().NumberOfChecks()), | 1447 num_variants_(call->NumberOfChecks()), |
1451 variants_(num_variants_), | 1448 variants_(call->targets_), |
1452 inlined_variants_(num_variants_), | 1449 inlined_variants_(), |
1453 non_inlined_variants_(num_variants_), | 1450 non_inlined_variants_(new (zone()) CallTargets()), |
1454 inlined_entries_(num_variants_), | 1451 inlined_entries_(num_variants_), |
1455 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), | 1452 exit_collector_(new (Z) InlineExitCollector(owner->caller_graph(), call)), |
1456 caller_function_(caller_function), | 1453 caller_function_(caller_function), |
1457 caller_inlining_id_(caller_inlining_id) {} | 1454 caller_inlining_id_(caller_inlining_id) {} |
1458 | 1455 |
1459 | 1456 |
1460 Isolate* PolymorphicInliner::isolate() const { | 1457 Isolate* PolymorphicInliner::isolate() const { |
1461 return owner_->caller_graph()->isolate(); | 1458 return owner_->caller_graph()->isolate(); |
1462 } | 1459 } |
1463 | 1460 |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1527 inlined_entries_.Add(join); | 1524 inlined_entries_.Add(join); |
1528 return true; | 1525 return true; |
1529 } | 1526 } |
1530 } | 1527 } |
1531 | 1528 |
1532 return false; | 1529 return false; |
1533 } | 1530 } |
1534 | 1531 |
1535 | 1532 |
1536 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { | 1533 bool PolymorphicInliner::CheckNonInlinedDuplicate(const Function& target) { |
1537 for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { | 1534 for (intptr_t i = 0; i < non_inlined_variants_->length(); ++i) { |
1538 if (target.raw() == non_inlined_variants_[i].target->raw()) { | 1535 if (target.raw() == non_inlined_variants_->At(i).target->raw()) { |
1539 return true; | 1536 return true; |
1540 } | 1537 } |
1541 } | 1538 } |
1542 | 1539 |
1543 return false; | 1540 return false; |
1544 } | 1541 } |
1545 | 1542 |
1546 | 1543 |
1547 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { | 1544 bool PolymorphicInliner::TryInliningPoly(const CidRangeTarget& range) { |
1548 if ((!FLAG_precompiled_mode || | 1545 if ((!FLAG_precompiled_mode || |
1549 owner_->inliner_->use_speculative_inlining()) && | 1546 owner_->inliner_->use_speculative_inlining()) && |
1550 range.cid_start == range.cid_end && | 1547 range.cid_start == range.cid_end && |
1551 TryInlineRecognizedMethod(range.cid_start, *range.target)) { | 1548 TryInlineRecognizedMethod(range.cid_start, *range.target)) { |
1552 owner_->inlined_ = true; | 1549 owner_->inlined_ = true; |
1553 return true; | 1550 return true; |
1554 } | 1551 } |
1555 | 1552 |
1556 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1553 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
1557 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1554 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
1558 arguments.Add(call_->PushArgumentAt(i)->value()); | 1555 arguments.Add(call_->PushArgumentAt(i)->value()); |
1559 } | 1556 } |
1560 InlinedCallData call_data(call_, &arguments, caller_function_, | 1557 InlinedCallData call_data(call_, &arguments, caller_function_, |
1561 caller_inlining_id_); | 1558 caller_inlining_id_); |
1562 if (!owner_->TryInlining(*range.target, | 1559 Function& target = Function::ZoneHandle(zone(), range.target->raw()); |
1563 call_->instance_call()->argument_names(), | 1560 if (!owner_->TryInlining(target, call_->instance_call()->argument_names(), |
1564 &call_data)) { | 1561 &call_data)) { |
1565 return false; | 1562 return false; |
1566 } | 1563 } |
1567 | 1564 |
1568 FlowGraph* callee_graph = call_data.callee_graph; | 1565 FlowGraph* callee_graph = call_data.callee_graph; |
1569 call_data.exit_collector->PrepareGraphs(callee_graph); | 1566 call_data.exit_collector->PrepareGraphs(callee_graph); |
1570 inlined_entries_.Add(callee_graph->graph_entry()); | 1567 inlined_entries_.Add(callee_graph->graph_entry()); |
1571 exit_collector_->Union(call_data.exit_collector); | 1568 exit_collector_->Union(call_data.exit_collector); |
1572 | 1569 |
1573 // Replace parameter stubs and constants. Replace the receiver argument | 1570 // Replace parameter stubs and constants. Replace the receiver argument |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1701 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1698 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
1702 const CidRangeTarget& variant = inlined_variants_[i]; | 1699 const CidRangeTarget& variant = inlined_variants_[i]; |
1703 bool test_is_range = (variant.cid_start != variant.cid_end); | 1700 bool test_is_range = (variant.cid_start != variant.cid_end); |
1704 bool is_last_test = (i == inlined_variants_.length() - 1); | 1701 bool is_last_test = (i == inlined_variants_.length() - 1); |
1705 // 1. Guard the body with a class id check. We don't need any check if | 1702 // 1. Guard the body with a class id check. We don't need any check if |
1706 // it's the last test and global analysis has told us that the call is | 1703 // it's the last test and global analysis has told us that the call is |
1707 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an | 1704 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an |
1708 // arbitrary CidRangeTarget. Currently we don't go into this branch if the | 1705 // arbitrary CidRangeTarget. Currently we don't go into this branch if the |
1709 // last test is a range test - instead we set the follow_with_deopt flag. | 1706 // last test is a range test - instead we set the follow_with_deopt flag. |
1710 if (is_last_test && (!test_is_range || call_->complete()) && | 1707 if (is_last_test && (!test_is_range || call_->complete()) && |
1711 non_inlined_variants_.is_empty()) { | 1708 non_inlined_variants_->is_empty()) { |
1712 // If it is the last variant use a check class id instruction which can | 1709 // If it is the last variant use a check class id instruction which can |
1713 // deoptimize, followed unconditionally by the body. Omit the check if | 1710 // deoptimize, followed unconditionally by the body. Omit the check if |
1714 // we know that we have covered all possible classes. | 1711 // we know that we have covered all possible classes. |
1715 if (!call_->complete()) { | 1712 if (!call_->complete()) { |
1716 ASSERT(!test_is_range); // See condition above. | 1713 ASSERT(!test_is_range); // See condition above. |
1717 RedefinitionInstr* cid_redefinition = | 1714 RedefinitionInstr* cid_redefinition = |
1718 new RedefinitionInstr(new (Z) Value(load_cid)); | 1715 new RedefinitionInstr(new (Z) Value(load_cid)); |
1719 cid_redefinition->set_ssa_temp_index( | 1716 cid_redefinition->set_ssa_temp_index( |
1720 owner_->caller_graph()->alloc_ssa_temp_index()); | 1717 owner_->caller_graph()->alloc_ssa_temp_index()); |
1721 cursor = AppendInstruction(cursor, cid_redefinition); | 1718 cursor = AppendInstruction(cursor, cid_redefinition); |
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1877 false_target2->InheritDeoptTarget(zone(), call_); | 1874 false_target2->InheritDeoptTarget(zone(), call_); |
1878 goto_1->InheritDeoptTarget(zone(), call_); | 1875 goto_1->InheritDeoptTarget(zone(), call_); |
1879 goto_2->InheritDeoptTarget(zone(), call_); | 1876 goto_2->InheritDeoptTarget(zone(), call_); |
1880 | 1877 |
1881 cursor = current_block = join; | 1878 cursor = current_block = join; |
1882 } | 1879 } |
1883 } | 1880 } |
1884 } | 1881 } |
1885 | 1882 |
1886 // Handle any non-inlined variants. | 1883 // Handle any non-inlined variants. |
1887 if (!non_inlined_variants_.is_empty()) { | 1884 if (!non_inlined_variants_->is_empty()) { |
1888 // Move push arguments of the call. | 1885 // Move push arguments of the call. |
1889 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1886 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
1890 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1887 PushArgumentInstr* push = call_->PushArgumentAt(i); |
1891 push->ReplaceUsesWith(push->value()->definition()); | 1888 push->ReplaceUsesWith(push->value()->definition()); |
1892 push->previous()->LinkTo(push->next()); | 1889 push->previous()->LinkTo(push->next()); |
1893 cursor->LinkTo(push); | 1890 cursor->LinkTo(push); |
1894 cursor = push; | 1891 cursor = push; |
1895 } | 1892 } |
1896 const ICData& old_checks = call_->ic_data(); | |
1897 const ICData& new_checks = ICData::ZoneHandle(ICData::New( | |
1898 Function::Handle(old_checks.Owner()), | |
1899 String::Handle(old_checks.target_name()), | |
1900 Array::Handle(old_checks.arguments_descriptor()), old_checks.deopt_id(), | |
1901 1, // Number of args tested. | |
1902 false)); // is_static_call | |
1903 for (intptr_t i = 0; i < non_inlined_variants_.length(); ++i) { | |
1904 // We are adding all the cids in each range. They will be joined | |
1905 // together again by the PolymorphicInstanceCall instruction, which is a | |
1906 // bit messy. | |
1907 intptr_t count = non_inlined_variants_[i].count; | |
1908 | |
1909 for (intptr_t j = non_inlined_variants_[i].cid_start; | |
1910 j <= non_inlined_variants_[i].cid_end; j++) { | |
1911 new_checks.AddReceiverCheck(j, *non_inlined_variants_[i].target, count); | |
1912 count = 0; | |
1913 } | |
1914 } | |
1915 PolymorphicInstanceCallInstr* fallback_call = | 1893 PolymorphicInstanceCallInstr* fallback_call = |
1916 new PolymorphicInstanceCallInstr(call_->instance_call(), new_checks, | 1894 new PolymorphicInstanceCallInstr( |
1917 /* with_checks = */ true, | 1895 call_->instance_call(), *non_inlined_variants_, |
1918 call_->complete()); | 1896 /* with_checks = */ true, call_->complete()); |
1919 fallback_call->set_ssa_temp_index( | 1897 fallback_call->set_ssa_temp_index( |
1920 owner_->caller_graph()->alloc_ssa_temp_index()); | 1898 owner_->caller_graph()->alloc_ssa_temp_index()); |
1921 fallback_call->InheritDeoptTarget(zone(), call_); | 1899 fallback_call->InheritDeoptTarget(zone(), call_); |
1922 fallback_call->set_total_call_count(call_->CallCount()); | 1900 fallback_call->set_total_call_count(call_->CallCount()); |
1923 ReturnInstr* fallback_return = new ReturnInstr( | 1901 ReturnInstr* fallback_return = new ReturnInstr( |
1924 call_->instance_call()->token_pos(), new Value(fallback_call)); | 1902 call_->instance_call()->token_pos(), new Value(fallback_call)); |
1925 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, | 1903 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, |
1926 fallback_call); | 1904 fallback_call); |
1927 AppendInstruction(AppendInstruction(cursor, fallback_call), | 1905 AppendInstruction(AppendInstruction(cursor, fallback_call), |
1928 fallback_return); | 1906 fallback_return); |
(...skipping 29 matching lines...) Expand all Loading... |
1958 percent, message); | 1936 percent, message); |
1959 } | 1937 } |
1960 | 1938 |
1961 | 1939 |
1962 bool PolymorphicInliner::trace_inlining() const { | 1940 bool PolymorphicInliner::trace_inlining() const { |
1963 return owner_->trace_inlining(); | 1941 return owner_->trace_inlining(); |
1964 } | 1942 } |
1965 | 1943 |
1966 | 1944 |
1967 void PolymorphicInliner::Inline() { | 1945 void PolymorphicInliner::Inline() { |
1968 // Consider the polymorphic variants in order by frequency. | 1946 ASSERT(&variants_ == &call_->targets_); |
1969 FlowGraphCompiler::SortICDataByCount(call_->ic_data(), &variants_, | 1947 |
1970 /* drop_smi = */ false); | |
1971 intptr_t total = call_->total_call_count(); | 1948 intptr_t total = call_->total_call_count(); |
1972 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { | 1949 for (intptr_t var_idx = 0; var_idx < variants_.length(); ++var_idx) { |
1973 if (variants_.length() > FLAG_max_polymorphic_checks) { | 1950 if (variants_.length() > FLAG_max_polymorphic_checks) { |
1974 non_inlined_variants_.Add(variants_[var_idx]); | 1951 non_inlined_variants_->Add(variants_[var_idx]); |
1975 continue; | 1952 continue; |
1976 } | 1953 } |
1977 | 1954 |
1978 // We we almost inlined all the cases then try a little harder to inline | 1955 // We we almost inlined all the cases then try a little harder to inline |
1979 // the last two, because it's a big win if we inline all of them (compiler | 1956 // the last two, because it's a big win if we inline all of them (compiler |
1980 // can see all side effects). | 1957 // can see all side effects). |
1981 const bool try_harder = (var_idx >= variants_.length() - 2) && | 1958 const bool try_harder = (var_idx >= variants_.length() - 2) && |
1982 non_inlined_variants_.length() == 0; | 1959 non_inlined_variants_->length() == 0; |
1983 const Function& target = *variants_[var_idx].target; | 1960 const Function& target = *variants_[var_idx].target; |
1984 const intptr_t count = variants_[var_idx].count; | 1961 const intptr_t count = variants_[var_idx].count; |
1985 | 1962 |
1986 intptr_t size = target.optimized_instruction_count(); | 1963 intptr_t size = target.optimized_instruction_count(); |
1987 bool small = (size != 0 && size < FLAG_inlining_size_threshold); | 1964 bool small = (size != 0 && size < FLAG_inlining_size_threshold); |
1988 | 1965 |
1989 // If it's less than 3% of the dispatches, we won't even consider | 1966 // If it's less than 3% of the dispatches, we won't even consider |
1990 // checking for the class ID and branching to another already-inlined | 1967 // checking for the class ID and branching to another already-inlined |
1991 // version. | 1968 // version. |
1992 if (!try_harder && count < (total >> 5)) { | 1969 if (!try_harder && count < (total >> 5)) { |
1993 TRACE_INLINING( | 1970 TRACE_INLINING( |
1994 TracePolyInlining(variants_[var_idx], total, "way too infrequent")); | 1971 TracePolyInlining(variants_[var_idx], total, "way too infrequent")); |
1995 non_inlined_variants_.Add(variants_[var_idx]); | 1972 non_inlined_variants_->Add(variants_[var_idx]); |
1996 continue; | 1973 continue; |
1997 } | 1974 } |
1998 | 1975 |
1999 // First check if this is the same target as an earlier inlined variant. | 1976 // First check if this is the same target as an earlier inlined variant. |
2000 if (CheckInlinedDuplicate(target)) { | 1977 if (CheckInlinedDuplicate(target)) { |
2001 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, | 1978 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, |
2002 "duplicate already inlined")); | 1979 "duplicate already inlined")); |
2003 inlined_variants_.Add(variants_[var_idx]); | 1980 inlined_variants_.Add(variants_[var_idx]); |
2004 continue; | 1981 continue; |
2005 } | 1982 } |
2006 | 1983 |
2007 // If it's less than 12% of the dispatches and it's not already inlined, we | 1984 // If it's less than 12% of the dispatches and it's not already inlined, we |
2008 // don't consider inlining. For very small functions we are willing to | 1985 // don't consider inlining. For very small functions we are willing to |
2009 // consider inlining for 6% of the cases. | 1986 // consider inlining for 6% of the cases. |
2010 if (!try_harder && count < (total >> (small ? 4 : 3))) { | 1987 if (!try_harder && count < (total >> (small ? 4 : 3))) { |
2011 TRACE_INLINING( | 1988 TRACE_INLINING( |
2012 TracePolyInlining(variants_[var_idx], total, "too infrequent")); | 1989 TracePolyInlining(variants_[var_idx], total, "too infrequent")); |
2013 non_inlined_variants_.Add(variants_[var_idx]); | 1990 non_inlined_variants_->Add(variants_[var_idx]); |
2014 continue; | 1991 continue; |
2015 } | 1992 } |
2016 | 1993 |
2017 // Also check if this is the same target as an earlier non-inlined | 1994 // Also check if this is the same target as an earlier non-inlined |
2018 // variant. If so and since inlining decisions are costly, do not try | 1995 // variant. If so and since inlining decisions are costly, do not try |
2019 // to inline this variant. | 1996 // to inline this variant. |
2020 if (CheckNonInlinedDuplicate(target)) { | 1997 if (CheckNonInlinedDuplicate(target)) { |
2021 TRACE_INLINING( | 1998 TRACE_INLINING( |
2022 TracePolyInlining(variants_[var_idx], total, "already not inlined")); | 1999 TracePolyInlining(variants_[var_idx], total, "already not inlined")); |
2023 non_inlined_variants_.Add(variants_[var_idx]); | 2000 non_inlined_variants_->Add(variants_[var_idx]); |
2024 continue; | 2001 continue; |
2025 } | 2002 } |
2026 | 2003 |
2027 // Make an inlining decision. | 2004 // Make an inlining decision. |
2028 if (TryInliningPoly(variants_[var_idx])) { | 2005 if (TryInliningPoly(variants_[var_idx])) { |
2029 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined")); | 2006 TRACE_INLINING(TracePolyInlining(variants_[var_idx], total, "inlined")); |
2030 inlined_variants_.Add(variants_[var_idx]); | 2007 inlined_variants_.Add(variants_[var_idx]); |
2031 } else { | 2008 } else { |
2032 TRACE_INLINING( | 2009 TRACE_INLINING( |
2033 TracePolyInlining(variants_[var_idx], total, "not inlined")); | 2010 TracePolyInlining(variants_[var_idx], total, "not inlined")); |
2034 non_inlined_variants_.Add(variants_[var_idx]); | 2011 non_inlined_variants_->Add(variants_[var_idx]); |
2035 } | 2012 } |
2036 } | 2013 } |
2037 | 2014 |
2038 // If there are no inlined variants, leave the call in place. | 2015 // If there are no inlined variants, leave the call in place. |
2039 if (inlined_variants_.is_empty()) return; | 2016 if (inlined_variants_.is_empty()) return; |
2040 | 2017 |
2041 // Now build a decision tree (a DAG because of shared inline variants) and | 2018 // Now build a decision tree (a DAG because of shared inline variants) and |
2042 // inline it at the call site. | 2019 // inline it at the call site. |
2043 TargetEntryInstr* entry = BuildDecisionGraph(); | 2020 TargetEntryInstr* entry = BuildDecisionGraph(); |
2044 exit_collector_->ReplaceCall(entry); | 2021 exit_collector_->ReplaceCall(entry); |
(...skipping 1787 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3832 } | 3809 } |
3833 | 3810 |
3834 default: | 3811 default: |
3835 return false; | 3812 return false; |
3836 } | 3813 } |
3837 } | 3814 } |
3838 | 3815 |
3839 | 3816 |
3840 } // namespace dart | 3817 } // namespace dart |
3841 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3818 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |