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 1526 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1537 } | 1537 } |
1538 } | 1538 } |
1539 | 1539 |
1540 return false; | 1540 return false; |
1541 } | 1541 } |
1542 | 1542 |
1543 | 1543 |
1544 bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) { | 1544 bool PolymorphicInliner::TryInliningPoly(const TargetInfo& target_info) { |
1545 if ((!FLAG_precompiled_mode || | 1545 if ((!FLAG_precompiled_mode || |
1546 owner_->inliner_->use_speculative_inlining()) && | 1546 owner_->inliner_->use_speculative_inlining()) && |
1547 target_info.cid_start == target_info.cid_end && | 1547 target_info.IsSingleCid() && |
1548 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { | 1548 TryInlineRecognizedMethod(target_info.cid_start, *target_info.target)) { |
1549 owner_->inlined_ = true; | 1549 owner_->inlined_ = true; |
1550 return true; | 1550 return true; |
1551 } | 1551 } |
1552 | 1552 |
1553 GrowableArray<Value*> arguments(call_->ArgumentCount()); | 1553 GrowableArray<Value*> arguments(call_->ArgumentCount()); |
1554 for (int i = 0; i < call_->ArgumentCount(); ++i) { | 1554 for (int i = 0; i < call_->ArgumentCount(); ++i) { |
1555 arguments.Add(call_->PushArgumentAt(i)->value()); | 1555 arguments.Add(call_->PushArgumentAt(i)->value()); |
1556 } | 1556 } |
1557 InlinedCallData call_data(call_, &arguments, caller_function_, | 1557 InlinedCallData call_data(call_, &arguments, caller_function_, |
(...skipping 10 matching lines...) Expand all Loading... |
1568 exit_collector_->Union(call_data.exit_collector); | 1568 exit_collector_->Union(call_data.exit_collector); |
1569 | 1569 |
1570 // Replace parameter stubs and constants. Replace the receiver argument | 1570 // Replace parameter stubs and constants. Replace the receiver argument |
1571 // with a redefinition to prevent code from the inlined body from being | 1571 // with a redefinition to prevent code from the inlined body from being |
1572 // hoisted above the inlined entry. | 1572 // hoisted above the inlined entry. |
1573 ASSERT(arguments.length() > 0); | 1573 ASSERT(arguments.length() > 0); |
1574 Value* actual = arguments[0]; | 1574 Value* actual = arguments[0]; |
1575 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); | 1575 RedefinitionInstr* redefinition = new (Z) RedefinitionInstr(actual->Copy(Z)); |
1576 redefinition->set_ssa_temp_index( | 1576 redefinition->set_ssa_temp_index( |
1577 owner_->caller_graph()->alloc_ssa_temp_index()); | 1577 owner_->caller_graph()->alloc_ssa_temp_index()); |
1578 if (target_info.cid_start == target_info.cid_end) { | 1578 if (target_info.IsSingleCid()) { |
1579 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); | 1579 redefinition->UpdateType(CompileType::FromCid(target_info.cid_start)); |
1580 } | 1580 } |
1581 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); | 1581 redefinition->InsertAfter(callee_graph->graph_entry()->normal_entry()); |
1582 Definition* stub = (*call_data.parameter_stubs)[0]; | 1582 Definition* stub = (*call_data.parameter_stubs)[0]; |
1583 stub->ReplaceUsesWith(redefinition); | 1583 stub->ReplaceUsesWith(redefinition); |
1584 | 1584 |
1585 for (intptr_t i = 1; i < arguments.length(); ++i) { | 1585 for (intptr_t i = 1; i < arguments.length(); ++i) { |
1586 actual = arguments[i]; | 1586 actual = arguments[i]; |
1587 if (actual != NULL) { | 1587 if (actual != NULL) { |
1588 stub = (*call_data.parameter_stubs)[i]; | 1588 stub = (*call_data.parameter_stubs)[i]; |
(...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1687 BlockEntryInstr* current_block = entry; | 1687 BlockEntryInstr* current_block = entry; |
1688 Instruction* cursor = entry; | 1688 Instruction* cursor = entry; |
1689 | 1689 |
1690 Definition* receiver = call_->ArgumentAt(0); | 1690 Definition* receiver = call_->ArgumentAt(0); |
1691 // There are at least two variants including non-inlined ones, so we have | 1691 // There are at least two variants including non-inlined ones, so we have |
1692 // at least one branch on the class id. | 1692 // at least one branch on the class id. |
1693 LoadClassIdInstr* load_cid = | 1693 LoadClassIdInstr* load_cid = |
1694 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); | 1694 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); |
1695 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); | 1695 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); |
1696 cursor = AppendInstruction(cursor, load_cid); | 1696 cursor = AppendInstruction(cursor, load_cid); |
1697 bool follow_with_deopt = false; | |
1698 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1697 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
1699 const CidRange& variant = inlined_variants_[i]; | 1698 const CidRange& variant = inlined_variants_[i]; |
1700 bool test_is_range = (variant.cid_start != variant.cid_end); | 1699 bool test_is_range = !variant.IsSingleCid(); |
1701 bool is_last_test = (i == inlined_variants_.length() - 1); | 1700 bool is_last_test = (i == inlined_variants_.length() - 1); |
1702 // 1. Guard the body with a class id check. We don't need any check if | 1701 // 1. Guard the body with a class id check. We don't need any check if |
1703 // it's the last test and global analysis has told us that the call is | 1702 // it's the last test and global analysis has told us that the call is |
1704 // complete. TODO(erikcorry): Enhance CheckClassIdInstr so it can take an | 1703 // complete. |
1705 // arbitrary CidRangeTarget. Currently we don't go into this branch if the | 1704 if (is_last_test && non_inlined_variants_->is_empty()) { |
1706 // last test is a range test - instead we set the follow_with_deopt flag. | |
1707 if (is_last_test && (!test_is_range || call_->complete()) && | |
1708 non_inlined_variants_->is_empty()) { | |
1709 // If it is the last variant use a check class id instruction which can | 1705 // If it is the last variant use a check class id instruction which can |
1710 // deoptimize, followed unconditionally by the body. Omit the check if | 1706 // deoptimize, followed unconditionally by the body. Omit the check if |
1711 // we know that we have covered all possible classes. | 1707 // we know that we have covered all possible classes. |
1712 if (!call_->complete()) { | 1708 if (!call_->complete()) { |
1713 ASSERT(!test_is_range); // See condition above. | |
1714 RedefinitionInstr* cid_redefinition = | 1709 RedefinitionInstr* cid_redefinition = |
1715 new RedefinitionInstr(new (Z) Value(load_cid)); | 1710 new RedefinitionInstr(new (Z) Value(load_cid)); |
1716 cid_redefinition->set_ssa_temp_index( | 1711 cid_redefinition->set_ssa_temp_index( |
1717 owner_->caller_graph()->alloc_ssa_temp_index()); | 1712 owner_->caller_graph()->alloc_ssa_temp_index()); |
1718 cursor = AppendInstruction(cursor, cid_redefinition); | 1713 cursor = AppendInstruction(cursor, cid_redefinition); |
1719 CheckClassIdInstr* check_class_id = | 1714 CheckClassIdInstr* check_class_id = new (Z) CheckClassIdInstr( |
1720 new (Z) CheckClassIdInstr(new (Z) Value(cid_redefinition), | 1715 new (Z) Value(cid_redefinition), variant, call_->deopt_id()); |
1721 variant.cid_start, call_->deopt_id()); | |
1722 check_class_id->InheritDeoptTarget(zone(), call_); | 1716 check_class_id->InheritDeoptTarget(zone(), call_); |
1723 cursor = AppendInstruction(cursor, check_class_id); | 1717 cursor = AppendInstruction(cursor, check_class_id); |
1724 } | 1718 } |
1725 | 1719 |
1726 // The next instruction is the first instruction of the inlined body. | 1720 // The next instruction is the first instruction of the inlined body. |
1727 // Handle the two possible cases (unshared and shared subsequent | 1721 // Handle the two possible cases (unshared and shared subsequent |
1728 // predecessors) separately. | 1722 // predecessors) separately. |
1729 BlockEntryInstr* callee_entry = inlined_entries_[i]; | 1723 BlockEntryInstr* callee_entry = inlined_entries_[i]; |
1730 if (callee_entry->IsGraphEntry()) { | 1724 if (callee_entry->IsGraphEntry()) { |
1731 // Unshared. Graft the normal entry on after the check class | 1725 // Unshared. Graft the normal entry on after the check class |
(...skipping 21 matching lines...) Expand all Loading... |
1753 goto_join->InheritDeoptTarget(zone(), join); | 1747 goto_join->InheritDeoptTarget(zone(), join); |
1754 cursor->LinkTo(goto_join); | 1748 cursor->LinkTo(goto_join); |
1755 current_block->set_last_instruction(goto_join); | 1749 current_block->set_last_instruction(goto_join); |
1756 } else { | 1750 } else { |
1757 // There is no possibility of a TargetEntry (the first entry to a | 1751 // There is no possibility of a TargetEntry (the first entry to a |
1758 // shared inlined body) because this is the last inlined entry. | 1752 // shared inlined body) because this is the last inlined entry. |
1759 UNREACHABLE(); | 1753 UNREACHABLE(); |
1760 } | 1754 } |
1761 cursor = NULL; | 1755 cursor = NULL; |
1762 } else { | 1756 } else { |
1763 if (is_last_test && test_is_range) follow_with_deopt = true; | |
1764 // For all variants except the last, use a branch on the loaded class | 1757 // For all variants except the last, use a branch on the loaded class |
1765 // id. | 1758 // id. |
1766 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start)); | 1759 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start)); |
1767 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid); | 1760 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid); |
1768 BranchInstr* branch; | 1761 BranchInstr* branch; |
1769 BranchInstr* upper_limit_branch = NULL; | 1762 BranchInstr* upper_limit_branch = NULL; |
1770 BlockEntryInstr* cid_test_entry_block = current_block; | 1763 BlockEntryInstr* cid_test_entry_block = current_block; |
1771 if (test_is_range) { | 1764 if (test_is_range) { |
1772 // Double branch for testing a range of Cids. TODO(erikcorry): Make a | 1765 // Double branch for testing a range of Cids. TODO(erikcorry): Make a |
1773 // special instruction that uses subtraction and unsigned comparison to | 1766 // special instruction that uses subtraction and unsigned comparison to |
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1900 fallback_call->set_total_call_count(call_->CallCount()); | 1893 fallback_call->set_total_call_count(call_->CallCount()); |
1901 ReturnInstr* fallback_return = new ReturnInstr( | 1894 ReturnInstr* fallback_return = new ReturnInstr( |
1902 call_->instance_call()->token_pos(), new Value(fallback_call)); | 1895 call_->instance_call()->token_pos(), new Value(fallback_call)); |
1903 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, | 1896 fallback_return->InheritDeoptTargetAfter(owner_->caller_graph(), call_, |
1904 fallback_call); | 1897 fallback_call); |
1905 AppendInstruction(AppendInstruction(cursor, fallback_call), | 1898 AppendInstruction(AppendInstruction(cursor, fallback_call), |
1906 fallback_return); | 1899 fallback_return); |
1907 exit_collector_->AddExit(fallback_return); | 1900 exit_collector_->AddExit(fallback_return); |
1908 cursor = NULL; | 1901 cursor = NULL; |
1909 } else { | 1902 } else { |
1910 if (follow_with_deopt) { | |
1911 DeoptimizeInstr* deopt = new DeoptimizeInstr( | |
1912 ICData::kDeoptPolymorphicInstanceCallTestFail, call_->deopt_id()); | |
1913 deopt->InheritDeoptTarget(zone(), call_); | |
1914 cursor = AppendInstruction(cursor, deopt); | |
1915 cursor = NULL; | |
1916 } | |
1917 | |
1918 // Remove push arguments of the call. | 1903 // Remove push arguments of the call. |
1919 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1904 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
1920 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1905 PushArgumentInstr* push = call_->PushArgumentAt(i); |
1921 push->ReplaceUsesWith(push->value()->definition()); | 1906 push->ReplaceUsesWith(push->value()->definition()); |
1922 push->RemoveFromGraph(); | 1907 push->RemoveFromGraph(); |
1923 } | 1908 } |
1924 } | 1909 } |
1925 return entry; | 1910 return entry; |
1926 } | 1911 } |
1927 | 1912 |
(...skipping 1855 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3783 } | 3768 } |
3784 | 3769 |
3785 default: | 3770 default: |
3786 return false; | 3771 return false; |
3787 } | 3772 } |
3788 } | 3773 } |
3789 | 3774 |
3790 | 3775 |
3791 } // namespace dart | 3776 } // namespace dart |
3792 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3777 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |