Chromium Code Reviews| 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 720 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 731 const intptr_t num_checks = ic_data.NumberOfChecks(); | 731 const intptr_t num_checks = ic_data.NumberOfChecks(); |
| 732 for (intptr_t i = 0; i < num_checks; i++) { | 732 for (intptr_t i = 0; i < num_checks; i++) { |
| 733 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { | 733 if (ic_data.IsUsedAt(i) && ic_data.GetClassIdAt(i, arg_number) != cid) { |
| 734 return false; | 734 return false; |
| 735 } | 735 } |
| 736 } | 736 } |
| 737 return true; | 737 return true; |
| 738 } | 738 } |
| 739 | 739 |
| 740 | 740 |
| 741 bool AotOptimizer::TryReplaceWithIndexedOp(InstanceCallInstr* call) { | |
|
Florian Schneider
2016/06/24 16:09:58
I'd keep this code around:
FlowGraphInliner::TryI
Vyacheslav Egorov (Google)
2016/06/24 16:13:04
I think it does not make much sense to keep around
Florian Schneider
2016/06/24 22:48:17
We should make TryInlineRecognizedMethod work with
| |
| 742 // Check for monomorphic IC data. | |
| 743 if (!call->HasICData()) return false; | |
| 744 const ICData& ic_data = | |
| 745 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | |
| 746 if (ic_data.NumberOfChecks() != 1) { | |
| 747 return false; | |
| 748 } | |
| 749 return TryReplaceInstanceCallWithInline(call); | |
| 750 } | |
| 751 | |
| 752 | |
| 753 // Return true if d is a string of length one (a constant or result from | 741 // Return true if d is a string of length one (a constant or result from |
| 754 // from string-from-char-code instruction. | 742 // from string-from-char-code instruction. |
| 755 static bool IsLengthOneString(Definition* d) { | 743 static bool IsLengthOneString(Definition* d) { |
| 756 if (d->IsConstant()) { | 744 if (d->IsConstant()) { |
| 757 const Object& obj = d->AsConstant()->value(); | 745 const Object& obj = d->AsConstant()->value(); |
| 758 if (obj.IsString()) { | 746 if (obj.IsString()) { |
| 759 return String::Cast(obj).Length() == 1; | 747 return String::Cast(obj).Length() == 1; |
| 760 } else { | 748 } else { |
| 761 return false; | 749 return false; |
| 762 } | 750 } |
| (...skipping 859 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1622 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); | 1610 const Function& target = Function::Handle(Z, ic_data.GetTargetAt(0)); |
| 1623 if (target.kind() != RawFunction::kImplicitGetter) { | 1611 if (target.kind() != RawFunction::kImplicitGetter) { |
| 1624 // Non-implicit getters are inlined like normal methods by conventional | 1612 // Non-implicit getters are inlined like normal methods by conventional |
| 1625 // inlining in FlowGraphInliner. | 1613 // inlining in FlowGraphInliner. |
| 1626 return false; | 1614 return false; |
| 1627 } | 1615 } |
| 1628 return InlineImplicitInstanceGetter(call); | 1616 return InlineImplicitInstanceGetter(call); |
| 1629 } | 1617 } |
| 1630 | 1618 |
| 1631 | 1619 |
| 1632 bool AotOptimizer::TryReplaceInstanceCallWithInline( | |
| 1633 InstanceCallInstr* call) { | |
| 1634 Function& target = Function::Handle(Z); | |
| 1635 GrowableArray<intptr_t> class_ids; | |
| 1636 call->ic_data()->GetCheckAt(0, &class_ids, &target); | |
| 1637 const intptr_t receiver_cid = class_ids[0]; | |
| 1638 | |
| 1639 TargetEntryInstr* entry; | |
| 1640 Definition* last; | |
| 1641 if (!FlowGraphInliner::TryInlineRecognizedMethod(flow_graph_, | |
| 1642 receiver_cid, | |
| 1643 target, | |
| 1644 call, | |
| 1645 call->ArgumentAt(0), | |
| 1646 call->token_pos(), | |
| 1647 *call->ic_data(), | |
| 1648 &entry, &last)) { | |
| 1649 return false; | |
| 1650 } | |
| 1651 | |
| 1652 // Insert receiver class check. | |
| 1653 AddReceiverCheck(call); | |
| 1654 // Remove the original push arguments. | |
| 1655 for (intptr_t i = 0; i < call->ArgumentCount(); ++i) { | |
| 1656 PushArgumentInstr* push = call->PushArgumentAt(i); | |
| 1657 push->ReplaceUsesWith(push->value()->definition()); | |
| 1658 push->RemoveFromGraph(); | |
| 1659 } | |
| 1660 // Replace all uses of this definition with the result. | |
| 1661 call->ReplaceUsesWith(last); | |
| 1662 // Finally insert the sequence other definition in place of this one in the | |
| 1663 // graph. | |
| 1664 call->previous()->LinkTo(entry->next()); | |
| 1665 entry->UnuseAllInputs(); // Entry block is not in the graph. | |
| 1666 last->LinkTo(call); | |
| 1667 // Remove through the iterator. | |
| 1668 ASSERT(current_iterator()->Current() == call); | |
| 1669 current_iterator()->RemoveCurrentFromGraph(); | |
| 1670 call->set_previous(NULL); | |
| 1671 call->set_next(NULL); | |
| 1672 return true; | |
| 1673 } | |
| 1674 | |
| 1675 | |
| 1676 void AotOptimizer::ReplaceWithMathCFunction( | 1620 void AotOptimizer::ReplaceWithMathCFunction( |
| 1677 InstanceCallInstr* call, | 1621 InstanceCallInstr* call, |
| 1678 MethodRecognizer::Kind recognized_kind) { | 1622 MethodRecognizer::Kind recognized_kind) { |
| 1679 AddReceiverCheck(call); | 1623 AddReceiverCheck(call); |
| 1680 ZoneGrowableArray<Value*>* args = | 1624 ZoneGrowableArray<Value*>* args = |
| 1681 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); | 1625 new(Z) ZoneGrowableArray<Value*>(call->ArgumentCount()); |
| 1682 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { | 1626 for (intptr_t i = 0; i < call->ArgumentCount(); i++) { |
| 1683 args->Add(new(Z) Value(call->ArgumentAt(i))); | 1627 args->Add(new(Z) Value(call->ArgumentAt(i))); |
| 1684 } | 1628 } |
| 1685 InvokeMathCFunctionInstr* invoke = | 1629 InvokeMathCFunctionInstr* invoke = |
| 1686 new(Z) InvokeMathCFunctionInstr(args, | 1630 new(Z) InvokeMathCFunctionInstr(args, |
| 1687 call->deopt_id(), | 1631 call->deopt_id(), |
| 1688 recognized_kind, | 1632 recognized_kind, |
| 1689 call->token_pos()); | 1633 call->token_pos()); |
| 1690 ReplaceCall(call, invoke); | 1634 ReplaceCall(call, invoke); |
| 1691 } | 1635 } |
| 1692 | 1636 |
| 1693 | 1637 |
| 1694 static bool IsSupportedByteArrayViewCid(intptr_t cid) { | |
| 1695 switch (cid) { | |
| 1696 case kTypedDataInt8ArrayCid: | |
| 1697 case kTypedDataUint8ArrayCid: | |
| 1698 case kExternalTypedDataUint8ArrayCid: | |
| 1699 case kTypedDataUint8ClampedArrayCid: | |
| 1700 case kExternalTypedDataUint8ClampedArrayCid: | |
| 1701 case kTypedDataInt16ArrayCid: | |
| 1702 case kTypedDataUint16ArrayCid: | |
| 1703 case kTypedDataInt32ArrayCid: | |
| 1704 case kTypedDataUint32ArrayCid: | |
| 1705 case kTypedDataFloat32ArrayCid: | |
| 1706 case kTypedDataFloat64ArrayCid: | |
| 1707 case kTypedDataFloat32x4ArrayCid: | |
| 1708 case kTypedDataInt32x4ArrayCid: | |
| 1709 return true; | |
| 1710 default: | |
| 1711 return false; | |
| 1712 } | |
| 1713 } | |
| 1714 | |
| 1715 | |
| 1716 // Inline only simple, frequently called core library methods. | |
| 1717 bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) { | |
| 1718 ASSERT(call->HasICData()); | |
| 1719 const ICData& ic_data = *call->ic_data(); | |
| 1720 if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) { | |
| 1721 // No type feedback collected or multiple targets found. | |
| 1722 return false; | |
| 1723 } | |
| 1724 | |
| 1725 Function& target = Function::Handle(Z); | |
| 1726 GrowableArray<intptr_t> class_ids; | |
| 1727 ic_data.GetCheckAt(0, &class_ids, &target); | |
| 1728 MethodRecognizer::Kind recognized_kind = | |
| 1729 MethodRecognizer::RecognizeKind(target); | |
| 1730 | |
| 1731 if ((recognized_kind == MethodRecognizer::kGrowableArraySetData) && | |
| 1732 (ic_data.NumberOfChecks() == 1) && | |
| 1733 (class_ids[0] == kGrowableObjectArrayCid)) { | |
| 1734 // This is an internal method, no need to check argument types. | |
| 1735 Definition* array = call->ArgumentAt(0); | |
| 1736 Definition* value = call->ArgumentAt(1); | |
| 1737 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1738 GrowableObjectArray::data_offset(), | |
| 1739 new(Z) Value(array), | |
| 1740 new(Z) Value(value), | |
| 1741 kEmitStoreBarrier, | |
| 1742 call->token_pos()); | |
| 1743 ReplaceCall(call, store); | |
| 1744 return true; | |
| 1745 } | |
| 1746 | |
| 1747 if ((recognized_kind == MethodRecognizer::kGrowableArraySetLength) && | |
| 1748 (ic_data.NumberOfChecks() == 1) && | |
| 1749 (class_ids[0] == kGrowableObjectArrayCid)) { | |
| 1750 // This is an internal method, no need to check argument types nor | |
| 1751 // range. | |
| 1752 Definition* array = call->ArgumentAt(0); | |
| 1753 Definition* value = call->ArgumentAt(1); | |
| 1754 StoreInstanceFieldInstr* store = new(Z) StoreInstanceFieldInstr( | |
| 1755 GrowableObjectArray::length_offset(), | |
| 1756 new(Z) Value(array), | |
| 1757 new(Z) Value(value), | |
| 1758 kNoStoreBarrier, | |
| 1759 call->token_pos()); | |
| 1760 ReplaceCall(call, store); | |
| 1761 return true; | |
| 1762 } | |
| 1763 | |
| 1764 if ((recognized_kind == MethodRecognizer::kOneByteStringCodeUnitAt) || | |
| 1765 (recognized_kind == MethodRecognizer::kTwoByteStringCodeUnitAt) || | |
| 1766 (recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) || | |
| 1767 (recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt)) { | |
| 1768 ASSERT(ic_data.NumberOfChecks() == 1); | |
| 1769 ASSERT((class_ids[0] == kOneByteStringCid) || | |
| 1770 (class_ids[0] == kTwoByteStringCid) || | |
| 1771 (class_ids[0] == kExternalOneByteStringCid) || | |
| 1772 (class_ids[0] == kExternalTwoByteStringCid)); | |
| 1773 return TryReplaceInstanceCallWithInline(call); | |
| 1774 } | |
| 1775 | |
| 1776 if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) && | |
| 1777 (ic_data.NumberOfChecks() == 1)) { | |
| 1778 ASSERT((class_ids[0] == kOneByteStringCid) || | |
| 1779 (class_ids[0] == kTwoByteStringCid) || | |
| 1780 (class_ids[0] == kExternalOneByteStringCid) || | |
| 1781 (class_ids[0] == kExternalTwoByteStringCid)); | |
| 1782 return TryReplaceInstanceCallWithInline(call); | |
| 1783 } | |
| 1784 | |
| 1785 if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) { | |
| 1786 if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) { | |
| 1787 // This is an internal method, no need to check argument types nor | |
| 1788 // range. | |
| 1789 Definition* str = call->ArgumentAt(0); | |
| 1790 Definition* index = call->ArgumentAt(1); | |
| 1791 Definition* value = call->ArgumentAt(2); | |
| 1792 StoreIndexedInstr* store_op = new(Z) StoreIndexedInstr( | |
| 1793 new(Z) Value(str), | |
| 1794 new(Z) Value(index), | |
| 1795 new(Z) Value(value), | |
| 1796 kNoStoreBarrier, | |
| 1797 1, // Index scale | |
| 1798 kOneByteStringCid, | |
| 1799 call->deopt_id(), | |
| 1800 call->token_pos()); | |
| 1801 ReplaceCall(call, store_op); | |
| 1802 return true; | |
| 1803 } | |
| 1804 return false; | |
| 1805 } | |
| 1806 | |
| 1807 if (CanUnboxDouble() && | |
| 1808 (recognized_kind == MethodRecognizer::kIntegerToDouble) && | |
| 1809 (ic_data.NumberOfChecks() == 1)) { | |
| 1810 if (class_ids[0] == kSmiCid) { | |
| 1811 AddReceiverCheck(call); | |
| 1812 ReplaceCall(call, | |
| 1813 new(Z) SmiToDoubleInstr( | |
| 1814 new(Z) Value(call->ArgumentAt(0)), | |
| 1815 call->token_pos())); | |
| 1816 return true; | |
| 1817 } else if ((class_ids[0] == kMintCid) && CanConvertUnboxedMintToDouble()) { | |
| 1818 AddReceiverCheck(call); | |
| 1819 ReplaceCall(call, | |
| 1820 new(Z) MintToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), | |
| 1821 call->deopt_id())); | |
| 1822 return true; | |
| 1823 } | |
| 1824 } | |
| 1825 | |
| 1826 if (class_ids[0] == kDoubleCid) { | |
| 1827 if (!CanUnboxDouble()) { | |
| 1828 return false; | |
| 1829 } | |
| 1830 switch (recognized_kind) { | |
| 1831 case MethodRecognizer::kDoubleToInteger: { | |
| 1832 AddReceiverCheck(call); | |
| 1833 ASSERT(call->HasICData()); | |
| 1834 const ICData& ic_data = *call->ic_data(); | |
| 1835 Definition* input = call->ArgumentAt(0); | |
| 1836 Definition* d2i_instr = NULL; | |
| 1837 if (ic_data.HasDeoptReason(ICData::kDeoptDoubleToSmi)) { | |
| 1838 // Do not repeatedly deoptimize because result didn't fit into Smi. | |
| 1839 d2i_instr = new(Z) DoubleToIntegerInstr( | |
| 1840 new(Z) Value(input), call); | |
| 1841 } else { | |
| 1842 // Optimistically assume result fits into Smi. | |
| 1843 d2i_instr = new(Z) DoubleToSmiInstr( | |
| 1844 new(Z) Value(input), call->deopt_id()); | |
| 1845 } | |
| 1846 ReplaceCall(call, d2i_instr); | |
| 1847 return true; | |
| 1848 } | |
| 1849 case MethodRecognizer::kDoubleMod: | |
| 1850 case MethodRecognizer::kDoubleRound: | |
| 1851 ReplaceWithMathCFunction(call, recognized_kind); | |
| 1852 return true; | |
| 1853 case MethodRecognizer::kDoubleTruncate: | |
| 1854 case MethodRecognizer::kDoubleFloor: | |
| 1855 case MethodRecognizer::kDoubleCeil: | |
| 1856 if (!TargetCPUFeatures::double_truncate_round_supported()) { | |
| 1857 ReplaceWithMathCFunction(call, recognized_kind); | |
| 1858 } else { | |
| 1859 AddReceiverCheck(call); | |
| 1860 DoubleToDoubleInstr* d2d_instr = | |
| 1861 new(Z) DoubleToDoubleInstr(new(Z) Value(call->ArgumentAt(0)), | |
| 1862 recognized_kind, call->deopt_id()); | |
| 1863 ReplaceCall(call, d2d_instr); | |
| 1864 } | |
| 1865 return true; | |
| 1866 case MethodRecognizer::kDoubleAdd: | |
| 1867 case MethodRecognizer::kDoubleSub: | |
| 1868 case MethodRecognizer::kDoubleMul: | |
| 1869 case MethodRecognizer::kDoubleDiv: | |
| 1870 return TryReplaceInstanceCallWithInline(call); | |
| 1871 default: | |
| 1872 // Unsupported method. | |
| 1873 return false; | |
| 1874 } | |
| 1875 } | |
| 1876 | |
| 1877 if (IsSupportedByteArrayViewCid(class_ids[0]) && | |
| 1878 (ic_data.NumberOfChecks() == 1)) { | |
| 1879 return TryReplaceInstanceCallWithInline(call); | |
| 1880 } | |
| 1881 | |
| 1882 if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | |
| 1883 return TryInlineFloat32x4Method(call, recognized_kind); | |
| 1884 } | |
| 1885 | |
| 1886 if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) { | |
| 1887 return TryInlineInt32x4Method(call, recognized_kind); | |
| 1888 } | |
| 1889 | |
| 1890 if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) { | |
| 1891 return TryInlineFloat64x2Method(call, recognized_kind); | |
| 1892 } | |
| 1893 | |
| 1894 return false; | |
| 1895 } | |
| 1896 | |
| 1897 | |
| 1898 bool AotOptimizer::TryInlineFloat32x4Constructor( | 1638 bool AotOptimizer::TryInlineFloat32x4Constructor( |
| 1899 StaticCallInstr* call, | 1639 StaticCallInstr* call, |
| 1900 MethodRecognizer::Kind recognized_kind) { | 1640 MethodRecognizer::Kind recognized_kind) { |
| 1901 // Cannot handle unboxed instructions. | 1641 // Cannot handle unboxed instructions. |
| 1902 ASSERT(FLAG_precompiled_mode); | 1642 ASSERT(FLAG_precompiled_mode); |
| 1903 return false; | 1643 return false; |
| 1904 } | 1644 } |
| 1905 | 1645 |
| 1906 | 1646 |
| 1907 bool AotOptimizer::TryInlineFloat64x2Constructor( | 1647 bool AotOptimizer::TryInlineFloat64x2Constructor( |
| (...skipping 377 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2285 } | 2025 } |
| 2286 // If all of the inputs are known smis or the result of CheckedSmiOp, | 2026 // If all of the inputs are known smis or the result of CheckedSmiOp, |
| 2287 // we guess the operand to be likely smi. | 2027 // we guess the operand to be likely smi. |
| 2288 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { | 2028 for (intptr_t i = 0; i < instr->ArgumentCount(); ++i) { |
| 2289 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; | 2029 if (!instr->ArgumentAt(i)->IsCheckedSmiOp()) return false; |
| 2290 } | 2030 } |
| 2291 return true; | 2031 return true; |
| 2292 } | 2032 } |
| 2293 | 2033 |
| 2294 | 2034 |
| 2035 bool AotOptimizer::TryInlineFieldAccess(InstanceCallInstr* call) { | |
| 2036 const Token::Kind op_kind = call->token_kind(); | |
| 2037 if ((op_kind == Token::kGET) && TryInlineInstanceGetter(call)) { | |
| 2038 return true; | |
| 2039 } | |
| 2040 | |
| 2041 const ICData& unary_checks = | |
| 2042 ICData::Handle(Z, call->ic_data()->AsUnaryClassChecks()); | |
| 2043 if ((unary_checks.NumberOfChecks() > 0) && | |
| 2044 (op_kind == Token::kSET) && | |
| 2045 TryInlineInstanceSetter(call, unary_checks)) { | |
| 2046 return true; | |
| 2047 } | |
| 2048 | |
| 2049 return false; | |
| 2050 } | |
| 2051 | |
| 2052 | |
| 2295 // Tries to optimize instance call by replacing it with a faster instruction | 2053 // Tries to optimize instance call by replacing it with a faster instruction |
| 2296 // (e.g, binary op, field load, ..). | 2054 // (e.g, binary op, field load, ..). |
| 2297 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { | 2055 void AotOptimizer::VisitInstanceCall(InstanceCallInstr* instr) { |
| 2298 ASSERT(FLAG_precompiled_mode); | 2056 ASSERT(FLAG_precompiled_mode); |
| 2299 // TODO(srdjan): Investigate other attempts, as they are not allowed to | 2057 // TODO(srdjan): Investigate other attempts, as they are not allowed to |
| 2300 // deoptimize. | 2058 // deoptimize. |
| 2301 | 2059 |
| 2302 // Type test is special as it always gets converted into inlined code. | 2060 // Type test is special as it always gets converted into inlined code. |
| 2303 const Token::Kind op_kind = instr->token_kind(); | 2061 const Token::Kind op_kind = instr->token_kind(); |
| 2304 if (Token::IsTypeTestOperator(op_kind)) { | 2062 if (Token::IsTypeTestOperator(op_kind)) { |
| 2305 ReplaceWithInstanceOf(instr); | 2063 ReplaceWithInstanceOf(instr); |
| 2306 return; | 2064 return; |
| 2307 } | 2065 } |
| 2308 if (Token::IsTypeCastOperator(op_kind)) { | 2066 if (Token::IsTypeCastOperator(op_kind)) { |
| 2309 ReplaceWithTypeCast(instr); | 2067 ReplaceWithTypeCast(instr); |
| 2310 return; | 2068 return; |
| 2311 } | 2069 } |
| 2312 | 2070 |
| 2313 if ((op_kind == Token::kGET) && | 2071 if (TryInlineFieldAccess(instr)) { |
| 2314 TryInlineInstanceGetter(instr)) { | |
| 2315 return; | |
| 2316 } | |
| 2317 const ICData& unary_checks = | |
| 2318 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
| 2319 if ((unary_checks.NumberOfChecks() > 0) && | |
| 2320 (op_kind == Token::kSET) && | |
| 2321 TryInlineInstanceSetter(instr, unary_checks)) { | |
| 2322 return; | 2072 return; |
| 2323 } | 2073 } |
| 2324 | 2074 |
| 2075 const ICData& unary_checks = | |
| 2076 ICData::ZoneHandle(Z, instr->ic_data()->AsUnaryClassChecks()); | |
| 2325 if (IsAllowedForInlining(instr->deopt_id()) && | 2077 if (IsAllowedForInlining(instr->deopt_id()) && |
| 2326 (unary_checks.NumberOfChecks() > 0)) { | 2078 (unary_checks.NumberOfChecks() > 0)) { |
| 2327 if ((op_kind == Token::kINDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2328 return; | |
| 2329 } | |
| 2330 if ((op_kind == Token::kASSIGN_INDEX) && TryReplaceWithIndexedOp(instr)) { | |
| 2331 return; | |
| 2332 } | |
| 2333 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { | 2079 if ((op_kind == Token::kEQ) && TryReplaceWithEqualityOp(instr, op_kind)) { |
| 2334 return; | 2080 return; |
| 2335 } | 2081 } |
| 2336 | 2082 |
| 2337 if (Token::IsRelationalOperator(op_kind) && | 2083 if (Token::IsRelationalOperator(op_kind) && |
| 2338 TryReplaceWithRelationalOp(instr, op_kind)) { | 2084 TryReplaceWithRelationalOp(instr, op_kind)) { |
| 2339 return; | 2085 return; |
| 2340 } | 2086 } |
| 2341 | 2087 |
| 2342 if (Token::IsBinaryOperator(op_kind) && | 2088 if (Token::IsBinaryOperator(op_kind) && |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2506 | 2252 |
| 2507 single_target = Function::null(); | 2253 single_target = Function::null(); |
| 2508 } | 2254 } |
| 2509 | 2255 |
| 2510 ASSERT(ic_data.raw() != ICData::null()); | 2256 ASSERT(ic_data.raw() != ICData::null()); |
| 2511 ASSERT(single_target.raw() == Function::null()); | 2257 ASSERT(single_target.raw() == Function::null()); |
| 2512 ic_data.AddReceiverCheck(cid, target); | 2258 ic_data.AddReceiverCheck(cid, target); |
| 2513 } | 2259 } |
| 2514 | 2260 |
| 2515 if (single_target.raw() != Function::null()) { | 2261 if (single_target.raw() != Function::null()) { |
| 2262 // If this is a getter or setter invocation try inlining it right away | |
| 2263 // instead of replacing it with a static call. | |
| 2264 if ((op_kind == Token::kGET) || (op_kind == Token::kSET)) { | |
| 2265 // Create fake IC data with the resolved target. | |
| 2266 const ICData& ic_data = ICData::Handle( | |
| 2267 ICData::New(flow_graph_->function(), | |
| 2268 instr->function_name(), | |
| 2269 args_desc_array, | |
| 2270 Thread::kNoDeoptId, | |
| 2271 /* args_tested = */ 1, | |
| 2272 false)); | |
| 2273 cls = single_target.Owner(); | |
| 2274 ic_data.AddReceiverCheck(cls.id(), single_target); | |
| 2275 instr->set_ic_data(&ic_data); | |
| 2276 | |
| 2277 if (TryInlineFieldAccess(instr)) { | |
| 2278 return; | |
| 2279 } | |
| 2280 } | |
| 2281 | |
| 2516 // We have computed that there is only a single target for this call | 2282 // We have computed that there is only a single target for this call |
| 2517 // within the whole hierarchy. Replace InstanceCall with StaticCall. | 2283 // within the whole hierarchy. Replace InstanceCall with StaticCall. |
| 2518 ZoneGrowableArray<PushArgumentInstr*>* args = | 2284 ZoneGrowableArray<PushArgumentInstr*>* args = |
| 2519 new (Z) ZoneGrowableArray<PushArgumentInstr*>( | 2285 new (Z) ZoneGrowableArray<PushArgumentInstr*>( |
| 2520 instr->ArgumentCount()); | 2286 instr->ArgumentCount()); |
| 2521 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { | 2287 for (intptr_t i = 0; i < instr->ArgumentCount(); i++) { |
| 2522 args->Add(instr->PushArgumentAt(i)); | 2288 args->Add(instr->PushArgumentAt(i)); |
| 2523 } | 2289 } |
| 2524 StaticCallInstr* call = new (Z) StaticCallInstr( | 2290 StaticCallInstr* call = new (Z) StaticCallInstr( |
| 2525 instr->token_pos(), | 2291 instr->token_pos(), |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2778 | 2544 |
| 2779 // Discard the environment from the original instruction because the store | 2545 // Discard the environment from the original instruction because the store |
| 2780 // can't deoptimize. | 2546 // can't deoptimize. |
| 2781 instr->RemoveEnvironment(); | 2547 instr->RemoveEnvironment(); |
| 2782 ReplaceCall(instr, store); | 2548 ReplaceCall(instr, store); |
| 2783 return true; | 2549 return true; |
| 2784 } | 2550 } |
| 2785 | 2551 |
| 2786 | 2552 |
| 2787 } // namespace dart | 2553 } // namespace dart |
| OLD | NEW |