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 1654 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1665 | 1665 |
1666 Definition* receiver = call_->ArgumentAt(0); | 1666 Definition* receiver = call_->ArgumentAt(0); |
1667 // There are at least two variants including non-inlined ones, so we have | 1667 // There are at least two variants including non-inlined ones, so we have |
1668 // at least one branch on the class id. | 1668 // at least one branch on the class id. |
1669 LoadClassIdInstr* load_cid = | 1669 LoadClassIdInstr* load_cid = |
1670 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); | 1670 new (Z) LoadClassIdInstr(new (Z) Value(receiver)); |
1671 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); | 1671 load_cid->set_ssa_temp_index(owner_->caller_graph()->alloc_ssa_temp_index()); |
1672 cursor = AppendInstruction(cursor, load_cid); | 1672 cursor = AppendInstruction(cursor, load_cid); |
1673 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { | 1673 for (intptr_t i = 0; i < inlined_variants_.length(); ++i) { |
1674 const CidRange& variant = inlined_variants_[i]; | 1674 const CidRange& variant = inlined_variants_[i]; |
1675 bool test_is_range = !variant.IsSingleCid(); | |
1676 bool is_last_test = (i == inlined_variants_.length() - 1); | 1675 bool is_last_test = (i == inlined_variants_.length() - 1); |
1677 // 1. Guard the body with a class id check. We don't need any check if | 1676 // 1. Guard the body with a class id check. We don't need any check if |
1678 // it's the last test and global analysis has told us that the call is | 1677 // it's the last test and global analysis has told us that the call is |
1679 // complete. | 1678 // complete. |
1680 if (is_last_test && non_inlined_variants_->is_empty()) { | 1679 if (is_last_test && non_inlined_variants_->is_empty()) { |
1681 // If it is the last variant use a check class id instruction which can | 1680 // If it is the last variant use a check class id instruction which can |
1682 // deoptimize, followed unconditionally by the body. Omit the check if | 1681 // deoptimize, followed unconditionally by the body. Omit the check if |
1683 // we know that we have covered all possible classes. | 1682 // we know that we have covered all possible classes. |
1684 if (!call_->complete()) { | 1683 if (!call_->complete()) { |
1685 RedefinitionInstr* cid_redefinition = | 1684 RedefinitionInstr* cid_redefinition = |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1725 current_block->set_last_instruction(goto_join); | 1724 current_block->set_last_instruction(goto_join); |
1726 } else { | 1725 } else { |
1727 // There is no possibility of a TargetEntry (the first entry to a | 1726 // There is no possibility of a TargetEntry (the first entry to a |
1728 // shared inlined body) because this is the last inlined entry. | 1727 // shared inlined body) because this is the last inlined entry. |
1729 UNREACHABLE(); | 1728 UNREACHABLE(); |
1730 } | 1729 } |
1731 cursor = NULL; | 1730 cursor = NULL; |
1732 } else { | 1731 } else { |
1733 // For all variants except the last, use a branch on the loaded class | 1732 // For all variants except the last, use a branch on the loaded class |
1734 // id. | 1733 // id. |
1735 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start)); | 1734 ComparisonInstr* compare; |
1736 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid); | |
1737 BranchInstr* branch; | |
1738 BranchInstr* upper_limit_branch = NULL; | |
1739 BlockEntryInstr* cid_test_entry_block = current_block; | 1735 BlockEntryInstr* cid_test_entry_block = current_block; |
1740 if (test_is_range) { | 1736 if (variant.IsSingleCid()) { |
1741 // Double branch for testing a range of Cids. TODO(erikcorry): Make a | 1737 const Smi& cid = Smi::ZoneHandle(Smi::New(variant.cid_start)); |
1742 // special instruction that uses subtraction and unsigned comparison to | 1738 ConstantInstr* cid_constant = owner_->caller_graph()->GetConstant(cid); |
1743 // do this with a single branch. | 1739 compare = new StrictCompareInstr( |
1744 const Smi& cid_end = Smi::ZoneHandle(Smi::New(variant.cid_end)); | |
1745 ConstantInstr* cid_constant_end = | |
1746 owner_->caller_graph()->GetConstant(cid_end); | |
1747 RelationalOpInstr* compare_top = new RelationalOpInstr( | |
1748 call_->instance_call()->token_pos(), Token::kLTE, | |
1749 new Value(load_cid), new Value(cid_constant_end), kSmiCid, | |
1750 call_->deopt_id()); | |
1751 BranchInstr* branch_top = upper_limit_branch = | |
1752 new BranchInstr(compare_top, Thread::kNoDeoptId); | |
1753 branch_top->InheritDeoptTarget(zone(), call_); | |
1754 cursor = AppendInstruction(cursor, branch_top); | |
1755 current_block->set_last_instruction(branch_top); | |
1756 | |
1757 TargetEntryInstr* below_target = new TargetEntryInstr( | |
1758 AllocateBlockId(), try_idx, Thread::kNoDeoptId); | |
1759 below_target->InheritDeoptTarget(zone(), call_); | |
1760 current_block->AddDominatedBlock(below_target); | |
1761 cursor = current_block = below_target; | |
1762 *branch_top->true_successor_address() = below_target; | |
1763 | |
1764 RelationalOpInstr* compare_bottom = new RelationalOpInstr( | |
1765 call_->instance_call()->token_pos(), Token::kGTE, | |
1766 new Value(load_cid), new Value(cid_constant), kSmiCid, | |
1767 call_->deopt_id()); | |
1768 branch = new BranchInstr(compare_bottom, Thread::kNoDeoptId); | |
1769 } else { | |
1770 StrictCompareInstr* compare = new StrictCompareInstr( | |
1771 call_->instance_call()->token_pos(), Token::kEQ_STRICT, | 1740 call_->instance_call()->token_pos(), Token::kEQ_STRICT, |
1772 new Value(load_cid), new Value(cid_constant), | 1741 new Value(load_cid), new Value(cid_constant), |
1773 /* number_check = */ false, Thread::kNoDeoptId); | 1742 /* number_check = */ false, Thread::kNoDeoptId); |
1774 branch = new BranchInstr(compare, Thread::kNoDeoptId); | 1743 } else { |
| 1744 compare = new SmiRangeComparisonInstr( |
| 1745 call_->instance_call()->token_pos(), new Value(load_cid), |
| 1746 variant.cid_start, variant.cid_end); |
1775 } | 1747 } |
| 1748 BranchInstr* branch = new BranchInstr(compare, Thread::kNoDeoptId); |
1776 | 1749 |
1777 branch->InheritDeoptTarget(zone(), call_); | 1750 branch->InheritDeoptTarget(zone(), call_); |
1778 cursor = AppendInstruction(cursor, branch); | 1751 cursor = AppendInstruction(cursor, branch); |
1779 current_block->set_last_instruction(branch); | 1752 current_block->set_last_instruction(branch); |
1780 cursor = NULL; | 1753 cursor = NULL; |
1781 | 1754 |
1782 // 2. Handle a match by linking to the inlined body. There are three | 1755 // 2. Handle a match by linking to the inlined body. There are three |
1783 // cases (unshared, shared first predecessor, and shared subsequent | 1756 // cases (unshared, shared first predecessor, and shared subsequent |
1784 // predecessors). | 1757 // predecessors). |
1785 BlockEntryInstr* callee_entry = inlined_entries_[i]; | 1758 BlockEntryInstr* callee_entry = inlined_entries_[i]; |
(...skipping 30 matching lines...) Expand all Loading... |
1816 // 3. Prepare to handle a match failure on the next iteration or the | 1789 // 3. Prepare to handle a match failure on the next iteration or the |
1817 // fall-through code below for non-inlined variants. | 1790 // fall-through code below for non-inlined variants. |
1818 | 1791 |
1819 TargetEntryInstr* false_target = | 1792 TargetEntryInstr* false_target = |
1820 new TargetEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); | 1793 new TargetEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); |
1821 false_target->InheritDeoptTarget(zone(), call_); | 1794 false_target->InheritDeoptTarget(zone(), call_); |
1822 *branch->false_successor_address() = false_target; | 1795 *branch->false_successor_address() = false_target; |
1823 cid_test_entry_block->AddDominatedBlock(false_target); | 1796 cid_test_entry_block->AddDominatedBlock(false_target); |
1824 | 1797 |
1825 cursor = current_block = false_target; | 1798 cursor = current_block = false_target; |
1826 | |
1827 if (test_is_range) { | |
1828 // If we tested against a range of Cids there are two different tests | |
1829 // that can go to the no-cid-match target. | |
1830 JoinEntryInstr* join = | |
1831 new JoinEntryInstr(AllocateBlockId(), try_idx, Thread::kNoDeoptId); | |
1832 TargetEntryInstr* false_target2 = new TargetEntryInstr( | |
1833 AllocateBlockId(), try_idx, Thread::kNoDeoptId); | |
1834 *upper_limit_branch->false_successor_address() = false_target2; | |
1835 cid_test_entry_block->AddDominatedBlock(false_target2); | |
1836 cid_test_entry_block->AddDominatedBlock(join); | |
1837 GotoInstr* goto_1 = new GotoInstr(join, Thread::kNoDeoptId); | |
1838 GotoInstr* goto_2 = new GotoInstr(join, Thread::kNoDeoptId); | |
1839 false_target->LinkTo(goto_1); | |
1840 false_target2->LinkTo(goto_2); | |
1841 false_target->set_last_instruction(goto_1); | |
1842 false_target2->set_last_instruction(goto_2); | |
1843 | |
1844 join->InheritDeoptTarget(zone(), call_); | |
1845 false_target2->InheritDeoptTarget(zone(), call_); | |
1846 goto_1->InheritDeoptTarget(zone(), call_); | |
1847 goto_2->InheritDeoptTarget(zone(), call_); | |
1848 | |
1849 cursor = current_block = join; | |
1850 } | |
1851 } | 1799 } |
1852 } | 1800 } |
1853 | 1801 |
1854 // Handle any non-inlined variants. | 1802 // Handle any non-inlined variants. |
1855 if (!non_inlined_variants_->is_empty()) { | 1803 if (!non_inlined_variants_->is_empty()) { |
1856 // Move push arguments of the call. | 1804 // Move push arguments of the call. |
1857 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { | 1805 for (intptr_t i = 0; i < call_->ArgumentCount(); ++i) { |
1858 PushArgumentInstr* push = call_->PushArgumentAt(i); | 1806 PushArgumentInstr* push = call_->PushArgumentAt(i); |
1859 push->ReplaceUsesWith(push->value()->definition()); | 1807 push->ReplaceUsesWith(push->value()->definition()); |
1860 push->previous()->LinkTo(push->next()); | 1808 push->previous()->LinkTo(push->next()); |
(...skipping 1906 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3767 } | 3715 } |
3768 | 3716 |
3769 default: | 3717 default: |
3770 return false; | 3718 return false; |
3771 } | 3719 } |
3772 } | 3720 } |
3773 | 3721 |
3774 | 3722 |
3775 } // namespace dart | 3723 } // namespace dart |
3776 #endif // !defined(DART_PRECOMPILED_RUNTIME) | 3724 #endif // !defined(DART_PRECOMPILED_RUNTIME) |
OLD | NEW |