| 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 | 4 |
| 5 #include "vm/aot_optimizer.h" | 5 #include "vm/aot_optimizer.h" |
| 6 | 6 |
| 7 #include "vm/bit_vector.h" | 7 #include "vm/bit_vector.h" |
| 8 #include "vm/branch_optimizer.h" | 8 #include "vm/branch_optimizer.h" |
| 9 #include "vm/cha.h" | 9 #include "vm/cha.h" |
| 10 #include "vm/compiler.h" | 10 #include "vm/compiler.h" |
| (...skipping 728 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 739 | 739 |
| 740 | 740 |
| 741 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | 741 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { |
| 742 // Check for monomorphic IC data. | 742 // Check for monomorphic IC data. |
| 743 if (!call->HasICData()) return false; | 743 if (!call->HasICData()) return false; |
| 744 const ICData& ic_data = | 744 const ICData& ic_data = |
| 745 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | 745 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); |
| 746 if (ic_data.NumberOfChecks() != 1) { | 746 if (ic_data.NumberOfChecks() != 1) { |
| 747 return false; | 747 return false; |
| 748 } | 748 } |
| 749 return TryReplaceInstanceCallWithInline(call); | 749 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 750 flow_graph_, current_iterator(), call); |
| 750 } | 751 } |
| 751 | 752 |
| 752 | 753 |
| 753 // Return true if d is a string of length one (a constant or result from | 754 // Return true if d is a string of length one (a constant or result from |
| 754 // from string-from-char-code instruction. | 755 // from string-from-char-code instruction. |
| 755 static bool IsLengthOneString(Definition* d) { | 756 static bool IsLengthOneString(Definition* d) { |
| 756 if (d->IsConstant()) { | 757 if (d->IsConstant()) { |
| 757 const Object& obj = d->AsConstant()->value(); | 758 const Object& obj = d->AsConstant()->value(); |
| 758 if (obj.IsString()) { | 759 if (obj.IsString()) { |
| 759 return String::Cast(obj).Length() == 1; | 760 return String::Cast(obj).Length() == 1; |
| (...skipping 862 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1622 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 1623 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
| 1623 if (target.kind() != RawFunction::kImplicitGetter) { | 1624 if (target.kind() != RawFunction::kImplicitGetter) { |
| 1624 // Non-implicit getters are inlined like normal methods by conventional | 1625 // Non-implicit getters are inlined like normal methods by conventional |
| 1625 // inlining in FlowGraphInliner. | 1626 // inlining in FlowGraphInliner. |
| 1626 return false; | 1627 return false; |
| 1627 } | 1628 } |
| 1628 return InlineImplicitInstanceGetter(call); | 1629 return InlineImplicitInstanceGetter(call); |
| 1629 } | 1630 } |
| 1630 | 1631 |
| 1631 | 1632 |
| 1632 bool AotOptimizer::TryReplaceInstanceCallWithInline( | |
| 1633 InstanceCallInstr* call) { | |
| 1634 if (!IsAllowedForInlining(call->deopt_id())) return false; | |
| 1635 Function& target = Function::Handle(Z); | |
| 1636 GrowableArray<intptr_t> class_ids; | |
| 1637 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 1638 const intptr_t receiver_cid = class_ids[0]; | |
| 1639 | |
| 1640 TargetEntryInstr* entry; | |
| 1641 Definition* last; | |
| 1642 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, | |
| 1643 receiver_cid, | |
| 1644 target, | |
| 1645 call, | |
| 1646 call->ArgumentAt(0), | |
| 1647 call->token_pos(), | |
| 1648 *call->ic_data(), | |
| 1649 &entry, &last)) { | |
| 1650 return false; | |
| 1651 } | |
| 1652 | |
| 1653 // Insert receiver class check. | |
| 1654 AddReceiverCheck(call); | |
| 1655 // Remove the original push arguments. | |
| 1656 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 1657 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 1658 push->ReplaceUsesWith(push->value()->definition()); | |
| 1659 push->RemoveFromGraph(); | |
| 1660 } | |
| 1661 // Replace all uses of this definition with the result. | |
| 1662 call->ReplaceUsesWith(last); | |
| 1663 // Finally insert the sequence other definition in place of this one in the | |
| 1664 // graph. | |
| 1665 call->previous()->LinkTo(entry->next()); | |
| 1666 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 1667 last->LinkTo(call); | |
| 1668 // Remove through the iterator. | |
| 1669 ASSERT(current_iterator()->Current() == call); | |
| 1670 current_iterator()->RemoveCurrentFromGraph(); | |
| 1671 call->set_previous(NULL); | |
| 1672 call->set_next(NULL); | |
| 1673 return true; | |
| 1674 } | |
| 1675 | |
| 1676 | |
| 1677 void AotOptimizer::ReplaceWithMathCFunction( | 1633 void AotOptimizer::ReplaceWithMathCFunction( |
| 1678 InstanceCallInstr* call, | 1634 InstanceCallInstr* call, |
| 1679 MethodRecognizer::Kind recognized_kind) { | 1635 MethodRecognizer::Kind recognized_kind) { |
| 1680 AddReceiverCheck(call); | 1636 AddReceiverCheck(call); |
| 1681 ZoneGrowableArray<Value*>* args = | 1637 ZoneGrowableArray<Value*>* args = |
| 1682 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1638 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1683 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1639 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1684 args->Add(new(Z) Value(call->ArgumentAt(i))); | 1640 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 1685 } | 1641 } |
| 1686 InvokeMathCFunctionInstr* invoke = | 1642 InvokeMathCFunctionInstr* invoke = |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1722 // No type feedback collected or multiple targets found. | 1678 // No type feedback collected or multiple targets found. |
| 1723 return false; | 1679 return false; |
| 1724 } | 1680 } |
| 1725 | 1681 |
| 1726 Function& target = Function::Handle(Z); | 1682 Function& target = Function::Handle(Z); |
| 1727 GrowableArray<intptr_t> class_ids; | 1683 GrowableArray<intptr_t> class_ids; |
| 1728 ic_data.GetCheckAt(0, &class_ids, &target); | 1684 ic_data.GetCheckAt(0, &class_ids, &target); |
| 1729 MethodRecognizer::Kind recognized_kind = | 1685 MethodRecognizer::Kind recognized_kind = |
| 1730 MethodRecognizer::RecognizeKind(target); | 1686 MethodRecognizer::RecognizeKind(target); |
| 1731 | 1687 |
| 1732 if ((recognized_kind == MethodRecognizer::kGrowableArraySetData) && | |
| 1733 (ic_data.NumberOfChecks() == 1) && | |
| 1734 (class_ids[0] == kGrowableObjectArrayCid)) { | |
| 1735 // This is an internal method, no need to check argument types. | |
| 1736 Definition* array = call->ArgumentAt(0); | |
| 1737 Definition* value = call->ArgumentAt(1); | |
| 1738 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1739 GrowableObjectArray::data_offset(), | |
| 1740 new(Z) Value(array), | |
| 1741 new(Z) Value(value), | |
| 1742 kEmitStoreBarrier, | |
| 1743 call->token_pos()); | |
| 1744 ReplaceCall(call, store); | |
| 1745 return true; | |
| 1746 } | |
| 1747 | |
| 1748 if ((recognized_kind == MethodRecognizer::kGrowableArraySetLength) && | |
| 1749 (ic_data.NumberOfChecks() == 1) && | |
| 1750 (class_ids[0] == kGrowableObjectArrayCid)) { | |
| 1751 // This is an internal method, no need to check argument types nor | |
| 1752 // range. | |
| 1753 Definition* array = call->ArgumentAt(0); | |
| 1754 Definition* value = call->ArgumentAt(1); | |
| 1755 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1756 GrowableObjectArray::length_offset(), | |
| 1757 new(Z) Value(array), | |
| 1758 new(Z) Value(value), | |
| 1759 kNoStoreBarrier, | |
| 1760 call->token_pos()); | |
| 1761 ReplaceCall(call, store); | |
| 1762 return true; | |
| 1763 } | |
| 1764 | |
| 1765 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) || | 1688 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) || |
| 1766 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) || | 1689 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) || |
| 1767 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) || | 1690 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) || |
| 1768 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt)) { | 1691 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) || |
| 1692 (recognized_kind == MethodRecognizer::kGrowableArraySetData) || |
| 1693 (recognized_kind == MethodRecognizer::kGrowableArraySetLength)) { |
| 1769 ASSERT(ic_data.NumberOfChecks() == 1); | 1694 ASSERT(ic_data.NumberOfChecks() == 1); |
| 1770 ASSERT((class_ids[0] == kOneByteStringCid) || | 1695 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 1771 (class_ids[0] == kTwoByteStringCid) || | 1696 flow_graph_, current_iterator(), call); |
| 1772 (class_ids[0] == kExternalOneByteStringCid) || | |
| 1773 (class_ids[0] == kExternalTwoByteStringCid)); | |
| 1774 return TryReplaceInstanceCallWithInline(call); | |
| 1775 } | 1697 } |
| 1776 | 1698 |
| 1777 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && | 1699 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && |
| 1778 (ic_data.NumberOfChecks() == 1)) { | 1700 (ic_data.NumberOfChecks() == 1)) { |
| 1779 ASSERT((class_ids[0] == kOneByteStringCid) || | 1701 ASSERT((class_ids[0] == kOneByteStringCid) || |
| 1780 (class_ids[0] == kTwoByteStringCid) || | 1702 (class_ids[0] == kTwoByteStringCid) || |
| 1781 (class_ids[0] == kExternalOneByteStringCid) || | 1703 (class_ids[0] == kExternalOneByteStringCid) || |
| 1782 (class_ids[0] == kExternalTwoByteStringCid)); | 1704 (class_ids[0] == kExternalTwoByteStringCid)); |
| 1783 return TryReplaceInstanceCallWithInline(call); | 1705 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 1706 flow_graph_, current_iterator(), call); |
| 1784 } | 1707 } |
| 1785 | 1708 |
| 1786 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | 1709 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { |
| 1787 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | 1710 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { |
| 1788 // This is an internal method, no need to check argument types nor | 1711 // This is an internal method, no need to check argument types nor |
| 1789 // range. | 1712 // range. |
| 1790 Definition* str = call->ArgumentAt(0); | 1713 Definition* str = call->ArgumentAt(0); |
| 1791 Definition* index = call->ArgumentAt(1); | 1714 Definition* index = call->ArgumentAt(1); |
| 1792 Definition* value = call->ArgumentAt(2); | 1715 Definition* value = call->ArgumentAt(2); |
| 1793 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr( | 1716 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr( |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1861 DoubleToDoubleInstr* d2d_instr = | 1784 DoubleToDoubleInstr* d2d_instr = |
| 1862 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), | 1785 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), |
| 1863 recognized_kind, call->deopt_id()); | 1786 recognized_kind, call->deopt_id()); |
| 1864 ReplaceCall(call, d2d_instr); | 1787 ReplaceCall(call, d2d_instr); |
| 1865 } | 1788 } |
| 1866 return true; | 1789 return true; |
| 1867 case MethodRecognizer::kDoubleAdd: | 1790 case MethodRecognizer::kDoubleAdd: |
| 1868 case MethodRecognizer::kDoubleSub: | 1791 case MethodRecognizer::kDoubleSub: |
| 1869 case MethodRecognizer::kDoubleMul: | 1792 case MethodRecognizer::kDoubleMul: |
| 1870 case MethodRecognizer::kDoubleDiv: | 1793 case MethodRecognizer::kDoubleDiv: |
| 1871 return TryReplaceInstanceCallWithInline(call); | 1794 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 1795 flow_graph_, current_iterator(), call); |
| 1872 default: | 1796 default: |
| 1873 // Unsupported method. | 1797 // Unsupported method. |
| 1874 return false; | 1798 return false; |
| 1875 } | 1799 } |
| 1876 } | 1800 } |
| 1877 | 1801 |
| 1878 if (IsSupportedByteArrayViewCid(class_ids[0]) && | 1802 if (IsSupportedByteArrayViewCid(class_ids[0]) && |
| 1879 (ic_data.NumberOfChecks() == 1)) { | 1803 (ic_data.NumberOfChecks() == 1)) { |
| 1880 return TryReplaceInstanceCallWithInline(call); | 1804 return FlowGraphInliner::TryReplaceInstanceCallWithInline( |
| 1805 flow_graph_, current_iterator(), call); |
| 1881 } | 1806 } |
| 1882 | 1807 |
| 1883 if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | 1808 if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) { |
| 1884 return TryInlineFloat32x4Method(call, recognized_kind); | 1809 return TryInlineFloat32x4Method(call, recognized_kind); |
| 1885 } | 1810 } |
| 1886 | 1811 |
| 1887 if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | 1812 if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) { |
| 1888 return TryInlineInt32x4Method(call, recognized_kind); | 1813 return TryInlineInt32x4Method(call, recognized_kind); |
| 1889 } | 1814 } |
| 1890 | 1815 |
| (...skipping 924 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2815 | 2740 |
| 2816 // Discard the environment from the original instruction because the store | 2741 // Discard the environment from the original instruction because the store |
| 2817 // can't deoptimize. | 2742 // can't deoptimize. |
| 2818 instr->RemoveEnvironment(); | 2743 instr->RemoveEnvironment(); |
| 2819 ReplaceCall(instr, store); | 2744 ReplaceCall(instr, store); |
| 2820 return true; | 2745 return true; |
| 2821 } | 2746 } |
| 2822 | 2747 |
| 2823 | 2748 |
| 2824 } // namespace dart | 2749 } // namespace dart |
| OLD | NEW |