| 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->targets().HasSingleRecognizedTarget() && |
| 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->targets().HasSingleRecognizedTarget() || |
| 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 |