| 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/globals.h" // Needed here to get TARGET_ARCH_ARM. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
| 7 | 7 |
| 8 #include "vm/intermediate_language.h" | 8 #include "vm/intermediate_language.h" |
| 9 | 9 |
| 10 #include "vm/cpu.h" | 10 #include "vm/cpu.h" |
| (...skipping 1581 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1592 const DRegister value_reg = EvenDRegisterOf(locs()->in(2).fpu_reg()); | 1592 const DRegister value_reg = EvenDRegisterOf(locs()->in(2).fpu_reg()); |
| 1593 __ vstmd(IA, index.reg(), value_reg, 2); | 1593 __ vstmd(IA, index.reg(), value_reg, 2); |
| 1594 break; | 1594 break; |
| 1595 } | 1595 } |
| 1596 default: | 1596 default: |
| 1597 UNREACHABLE(); | 1597 UNREACHABLE(); |
| 1598 } | 1598 } |
| 1599 } | 1599 } |
| 1600 | 1600 |
| 1601 | 1601 |
| 1602 LocationSummary* GuardFieldInstr::MakeLocationSummary(Isolate* isolate, | 1602 LocationSummary* GuardFieldClassInstr::MakeLocationSummary(Isolate* isolate, |
| 1603 bool opt) const { | 1603 bool opt) const { |
| 1604 const intptr_t kNumInputs = 1; | 1604 const intptr_t kNumInputs = 1; |
| 1605 LocationSummary* summary = new(isolate) LocationSummary( | 1605 LocationSummary* summary = new(isolate) LocationSummary( |
| 1606 isolate, kNumInputs, 0, LocationSummary::kNoCall); | 1606 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1607 summary->set_in(0, Location::RequiresRegister()); | 1607 summary->set_in(0, Location::RequiresRegister()); |
| 1608 const bool field_has_length = field().needs_length_check(); | 1608 |
| 1609 summary->AddTemp(Location::RequiresRegister()); | 1609 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1610 summary->AddTemp(Location::RequiresRegister()); | 1610 const intptr_t field_cid = field().guarded_cid(); |
| 1611 const bool need_field_temp_reg = | 1611 |
| 1612 field_has_length || (field().guarded_cid() == kIllegalCid); | 1612 const bool emit_full_guard = |
| 1613 if (need_field_temp_reg) { | 1613 !opt || (field_cid == kIllegalCid); |
| 1614 |
| 1615 const bool needs_value_cid_temp_reg = emit_full_guard || |
| 1616 ((value_cid == kDynamicCid) && (field_cid != kSmiCid)); |
| 1617 |
| 1618 const bool needs_field_temp_reg = emit_full_guard; |
| 1619 |
| 1620 if (needs_value_cid_temp_reg) { |
| 1614 summary->AddTemp(Location::RequiresRegister()); | 1621 summary->AddTemp(Location::RequiresRegister()); |
| 1615 } | 1622 } |
| 1623 |
| 1624 if (needs_field_temp_reg) { |
| 1625 summary->AddTemp(Location::RequiresRegister()); |
| 1626 } |
| 1627 |
| 1616 return summary; | 1628 return summary; |
| 1617 } | 1629 } |
| 1618 | 1630 |
| 1619 | 1631 |
| 1620 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1632 void GuardFieldClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1633 const intptr_t value_cid = value()->Type()->ToCid(); |
| 1621 const intptr_t field_cid = field().guarded_cid(); | 1634 const intptr_t field_cid = field().guarded_cid(); |
| 1622 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | 1635 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; |
| 1623 const intptr_t field_length = field().guarded_list_length(); | |
| 1624 const bool field_has_length = field().needs_length_check(); | |
| 1625 const bool needs_field_temp_reg = | |
| 1626 field_has_length || (field().guarded_cid() == kIllegalCid); | |
| 1627 if (field_has_length) { | |
| 1628 // Currently, we should only see final fields that remember length. | |
| 1629 ASSERT(field().is_final()); | |
| 1630 } | |
| 1631 | 1636 |
| 1632 if (field_cid == kDynamicCid) { | 1637 if (field_cid == kDynamicCid) { |
| 1633 ASSERT(!compiler->is_optimizing()); | 1638 ASSERT(!compiler->is_optimizing()); |
| 1634 return; // Nothing to emit. | 1639 return; // Nothing to emit. |
| 1635 } | 1640 } |
| 1636 | 1641 |
| 1637 const intptr_t value_cid = value()->Type()->ToCid(); | 1642 const bool emit_full_guard = |
| 1643 !compiler->is_optimizing() || (field_cid == kIllegalCid); |
| 1644 |
| 1645 const bool needs_value_cid_temp_reg = emit_full_guard || |
| 1646 ((value_cid == kDynamicCid) && (field_cid != kSmiCid)); |
| 1647 |
| 1648 const bool needs_field_temp_reg = emit_full_guard; |
| 1638 | 1649 |
| 1639 const Register value_reg = locs()->in(0).reg(); | 1650 const Register value_reg = locs()->in(0).reg(); |
| 1640 | 1651 |
| 1641 const Register value_cid_reg = locs()->temp(0).reg(); | 1652 const Register value_cid_reg = needs_value_cid_temp_reg ? |
| 1653 locs()->temp(0).reg() : kNoRegister; |
| 1642 | 1654 |
| 1643 const Register temp_reg = locs()->temp(1).reg(); | 1655 const Register field_reg = needs_field_temp_reg ? |
| 1644 | |
| 1645 Register field_reg = needs_field_temp_reg ? | |
| 1646 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; | 1656 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; |
| 1647 | 1657 |
| 1648 Label ok, fail_label; | 1658 Label ok, fail_label; |
| 1649 | 1659 |
| 1650 Label* deopt = compiler->is_optimizing() ? | 1660 Label* deopt = compiler->is_optimizing() ? |
| 1651 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; | 1661 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1652 | 1662 |
| 1653 Label* fail = (deopt != NULL) ? deopt : &fail_label; | 1663 Label* fail = (deopt != NULL) ? deopt : &fail_label; |
| 1654 | 1664 |
| 1655 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { | 1665 if (emit_full_guard) { |
| 1656 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) { | |
| 1657 // Currently we can't have different location summaries for optimized | |
| 1658 // and non-optimized code. So instead we manually pick up a register | |
| 1659 // that is known to be free because we know how non-optimizing compiler | |
| 1660 // allocates registers. | |
| 1661 field_reg = R2; | |
| 1662 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1663 } | |
| 1664 | |
| 1665 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | 1666 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
| 1666 | 1667 |
| 1667 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); | 1668 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); |
| 1668 FieldAddress field_nullability_operand( | 1669 FieldAddress field_nullability_operand( |
| 1669 field_reg, Field::is_nullable_offset()); | 1670 field_reg, Field::is_nullable_offset()); |
| 1670 FieldAddress field_length_operand( | |
| 1671 field_reg, Field::guarded_list_length_offset()); | |
| 1672 | |
| 1673 ASSERT(value_cid_reg != kNoRegister); | |
| 1674 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); | |
| 1675 | 1671 |
| 1676 if (value_cid == kDynamicCid) { | 1672 if (value_cid == kDynamicCid) { |
| 1677 LoadValueCid(compiler, value_cid_reg, value_reg); | 1673 LoadValueCid(compiler, value_cid_reg, value_reg); |
| 1678 Label skip_length_check; | |
| 1679 __ ldr(IP, field_cid_operand); | 1674 __ ldr(IP, field_cid_operand); |
| 1680 __ cmp(value_cid_reg, Operand(IP)); | 1675 __ cmp(value_cid_reg, Operand(IP)); |
| 1681 __ b(&skip_length_check, NE); | 1676 __ b(&ok, EQ); |
| 1682 if (field_has_length) { | |
| 1683 ASSERT(temp_reg != kNoRegister); | |
| 1684 // Field guard may have remembered list length, check it. | |
| 1685 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1686 __ ldr(temp_reg, | |
| 1687 FieldAddress(value_reg, Array::length_offset())); | |
| 1688 __ CompareImmediate(temp_reg, Smi::RawValue(field_length)); | |
| 1689 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1690 __ ldr(temp_reg, | |
| 1691 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1692 __ CompareImmediate(temp_reg, Smi::RawValue(field_length)); | |
| 1693 } else { | |
| 1694 ASSERT(field_cid == kIllegalCid); | |
| 1695 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1696 // At compile time we do not know the type of the field nor its | |
| 1697 // length. At execution time we may have set the class id and | |
| 1698 // list length so we compare the guarded length with the | |
| 1699 // list length here, without this check the list length could change | |
| 1700 // without triggering a deoptimization. | |
| 1701 Label check_array, length_compared, no_fixed_length; | |
| 1702 // If length is negative the length guard is either disabled or | |
| 1703 // has not been initialized, either way it is safe to skip the | |
| 1704 // length check. | |
| 1705 __ ldr(IP, field_length_operand); | |
| 1706 __ CompareImmediate(IP, 0); | |
| 1707 __ b(&skip_length_check, LT); | |
| 1708 __ CompareImmediate(value_cid_reg, kNullCid); | |
| 1709 __ b(&no_fixed_length, EQ); | |
| 1710 // Check for typed data array. | |
| 1711 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid); | |
| 1712 __ b(&no_fixed_length, GT); | |
| 1713 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid); | |
| 1714 // Could still be a regular array. | |
| 1715 __ b(&check_array, LT); | |
| 1716 __ ldr(temp_reg, | |
| 1717 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1718 __ ldr(IP, field_length_operand); | |
| 1719 __ cmp(temp_reg, Operand(IP)); | |
| 1720 __ b(&length_compared); | |
| 1721 // Check for regular array. | |
| 1722 __ Bind(&check_array); | |
| 1723 __ CompareImmediate(value_cid_reg, kImmutableArrayCid); | |
| 1724 __ b(&no_fixed_length, GT); | |
| 1725 __ CompareImmediate(value_cid_reg, kArrayCid); | |
| 1726 __ b(&no_fixed_length, LT); | |
| 1727 __ ldr(temp_reg, | |
| 1728 FieldAddress(value_reg, Array::length_offset())); | |
| 1729 __ ldr(IP, field_length_operand); | |
| 1730 __ cmp(temp_reg, Operand(IP)); | |
| 1731 __ b(&length_compared); | |
| 1732 __ Bind(&no_fixed_length); | |
| 1733 __ b(fail); | |
| 1734 __ Bind(&length_compared); | |
| 1735 // Following branch cannot not occur, fall through. | |
| 1736 } | |
| 1737 __ b(fail, NE); | |
| 1738 } | |
| 1739 __ Bind(&skip_length_check); | |
| 1740 __ ldr(IP, field_nullability_operand); | 1677 __ ldr(IP, field_nullability_operand); |
| 1741 __ cmp(value_cid_reg, Operand(IP)); | 1678 __ cmp(value_cid_reg, Operand(IP)); |
| 1742 } else if (value_cid == kNullCid) { | 1679 } else if (value_cid == kNullCid) { |
| 1743 __ ldr(value_cid_reg, field_nullability_operand); | 1680 __ ldr(value_cid_reg, field_nullability_operand); |
| 1744 __ CompareImmediate(value_cid_reg, value_cid); | 1681 __ CompareImmediate(value_cid_reg, value_cid); |
| 1745 } else { | 1682 } else { |
| 1746 Label skip_length_check; | |
| 1747 __ ldr(value_cid_reg, field_cid_operand); | 1683 __ ldr(value_cid_reg, field_cid_operand); |
| 1748 __ CompareImmediate(value_cid_reg, value_cid); | 1684 __ CompareImmediate(value_cid_reg, value_cid); |
| 1749 __ b(&skip_length_check, NE); | |
| 1750 if (field_has_length) { | |
| 1751 ASSERT(value_cid_reg != kNoRegister); | |
| 1752 ASSERT(temp_reg != kNoRegister); | |
| 1753 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1754 __ ldr(temp_reg, | |
| 1755 FieldAddress(value_reg, Array::length_offset())); | |
| 1756 __ CompareImmediate(temp_reg, Smi::RawValue(field_length)); | |
| 1757 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1758 __ ldr(temp_reg, | |
| 1759 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1760 __ CompareImmediate(temp_reg, Smi::RawValue(field_length)); | |
| 1761 } else if (field_cid != kIllegalCid) { | |
| 1762 ASSERT(field_cid != value_cid); | |
| 1763 ASSERT(field_length >= 0); | |
| 1764 // Field has a known class id and length. At compile time it is | |
| 1765 // known that the value's class id is not a fixed length list. | |
| 1766 __ b(fail); | |
| 1767 } else { | |
| 1768 ASSERT(field_cid == kIllegalCid); | |
| 1769 ASSERT(field_length == Field::kUnknownFixedLength); | |
| 1770 // Following jump cannot not occur, fall through. | |
| 1771 } | |
| 1772 __ b(fail, NE); | |
| 1773 } | |
| 1774 // Not identical, possibly null. | |
| 1775 __ Bind(&skip_length_check); | |
| 1776 } | 1685 } |
| 1777 __ b(&ok, EQ); | 1686 __ b(&ok, EQ); |
| 1778 | 1687 |
| 1779 __ ldr(IP, field_cid_operand); | 1688 // Check if the tracked state of the guarded field can be initialized |
| 1780 __ CompareImmediate(IP, kIllegalCid); | 1689 // inline. If the field needs length check we fall through to runtime |
| 1781 __ b(fail, NE); | 1690 // which is responsible for computing offset of the length field |
| 1691 // based on the class id. |
| 1692 // Length guard will be emitted separately when needed via GuardFieldLength |
| 1693 // instruction after GuardFieldClass. |
| 1694 if (!field().needs_length_check()) { |
| 1695 // Uninitialized field can be handled inline. Check if the |
| 1696 // field is still unitialized. |
| 1697 __ ldr(IP, field_cid_operand); |
| 1698 __ CompareImmediate(IP, kIllegalCid); |
| 1699 __ b(fail, NE); |
| 1782 | 1700 |
| 1783 if (value_cid == kDynamicCid) { | 1701 if (value_cid == kDynamicCid) { |
| 1784 __ str(value_cid_reg, field_cid_operand); | 1702 __ str(value_cid_reg, field_cid_operand); |
| 1785 __ str(value_cid_reg, field_nullability_operand); | 1703 __ str(value_cid_reg, field_nullability_operand); |
| 1786 if (field_has_length) { | 1704 } else { |
| 1787 Label check_array, length_set, no_fixed_length; | 1705 __ LoadImmediate(IP, value_cid); |
| 1788 __ CompareImmediate(value_cid_reg, kNullCid); | 1706 __ str(IP, field_cid_operand); |
| 1789 __ b(&no_fixed_length, EQ); | 1707 __ str(IP, field_nullability_operand); |
| 1790 // Check for typed data array. | |
| 1791 __ CompareImmediate(value_cid_reg, kTypedDataInt32x4ArrayCid); | |
| 1792 __ b(&no_fixed_length, GT); | |
| 1793 __ CompareImmediate(value_cid_reg, kTypedDataInt8ArrayCid); | |
| 1794 // Could still be a regular array. | |
| 1795 __ b(&check_array, LT); | |
| 1796 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1797 __ ldr(value_cid_reg, | |
| 1798 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1799 __ str(value_cid_reg, field_length_operand); | |
| 1800 __ b(&length_set); // Updated field length typed data array. | |
| 1801 // Check for regular array. | |
| 1802 __ Bind(&check_array); | |
| 1803 __ CompareImmediate(value_cid_reg, kImmutableArrayCid); | |
| 1804 __ b(&no_fixed_length, GT); | |
| 1805 __ CompareImmediate(value_cid_reg, kArrayCid); | |
| 1806 __ b(&no_fixed_length, LT); | |
| 1807 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1808 __ ldr(value_cid_reg, | |
| 1809 FieldAddress(value_reg, Array::length_offset())); | |
| 1810 __ str(value_cid_reg, field_length_operand); | |
| 1811 // Updated field length from regular array. | |
| 1812 __ b(&length_set); | |
| 1813 __ Bind(&no_fixed_length); | |
| 1814 __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength)); | |
| 1815 __ str(IP, field_length_operand); | |
| 1816 __ Bind(&length_set); | |
| 1817 } | 1708 } |
| 1818 } else { | 1709 |
| 1819 __ LoadImmediate(IP, value_cid); | 1710 if (deopt == NULL) { |
| 1820 __ str(IP, field_cid_operand); | 1711 ASSERT(!compiler->is_optimizing()); |
| 1821 __ str(IP, field_nullability_operand); | 1712 __ b(&ok); |
| 1822 if (field_has_length) { | |
| 1823 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) { | |
| 1824 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1825 __ ldr(value_cid_reg, | |
| 1826 FieldAddress(value_reg, Array::length_offset())); | |
| 1827 __ str(value_cid_reg, field_length_operand); | |
| 1828 } else if (RawObject::IsTypedDataClassId(value_cid)) { | |
| 1829 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1830 __ ldr(value_cid_reg, | |
| 1831 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1832 __ str(value_cid_reg, field_length_operand); | |
| 1833 } else { | |
| 1834 __ LoadImmediate(IP, Smi::RawValue(Field::kNoFixedLength)); | |
| 1835 __ str(IP, field_length_operand); | |
| 1836 } | |
| 1837 } | 1713 } |
| 1838 } | 1714 } |
| 1839 | 1715 |
| 1840 if (deopt == NULL) { | 1716 if (deopt == NULL) { |
| 1841 ASSERT(!compiler->is_optimizing()); | 1717 ASSERT(!compiler->is_optimizing()); |
| 1842 __ b(&ok); | |
| 1843 __ Bind(fail); | 1718 __ Bind(fail); |
| 1844 | 1719 |
| 1845 __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset())); | 1720 __ ldr(IP, FieldAddress(field_reg, Field::guarded_cid_offset())); |
| 1846 __ CompareImmediate(IP, kDynamicCid); | 1721 __ CompareImmediate(IP, kDynamicCid); |
| 1847 __ b(&ok, EQ); | 1722 __ b(&ok, EQ); |
| 1848 | 1723 |
| 1849 __ Push(field_reg); | 1724 __ Push(field_reg); |
| 1850 __ Push(value_reg); | 1725 __ Push(value_reg); |
| 1851 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); | 1726 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1852 __ Drop(2); // Drop the field and the value. | 1727 __ Drop(2); // Drop the field and the value. |
| 1853 } | 1728 } |
| 1854 } else { | 1729 } else { |
| 1855 ASSERT(compiler->is_optimizing()); | 1730 ASSERT(compiler->is_optimizing()); |
| 1856 ASSERT(deopt != NULL); | 1731 ASSERT(deopt != NULL); |
| 1732 |
| 1857 // Field guard class has been initialized and is known. | 1733 // Field guard class has been initialized and is known. |
| 1858 if (field_reg != kNoRegister) { | |
| 1859 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); | |
| 1860 } | |
| 1861 if (value_cid == kDynamicCid) { | 1734 if (value_cid == kDynamicCid) { |
| 1862 // Field's guarded class id is fixed by value's class id is not known. | 1735 // Field's guarded class id is fixed by value's class id is not known. |
| 1863 __ tst(value_reg, Operand(kSmiTagMask)); | 1736 __ tst(value_reg, Operand(kSmiTagMask)); |
| 1864 | 1737 |
| 1865 if (field_cid != kSmiCid) { | 1738 if (field_cid != kSmiCid) { |
| 1866 __ b(fail, EQ); | 1739 __ b(fail, EQ); |
| 1867 __ LoadClassId(value_cid_reg, value_reg); | 1740 __ LoadClassId(value_cid_reg, value_reg); |
| 1868 __ CompareImmediate(value_cid_reg, field_cid); | 1741 __ CompareImmediate(value_cid_reg, field_cid); |
| 1869 } | 1742 } |
| 1870 | 1743 |
| 1871 if (field_has_length) { | |
| 1872 __ b(fail, NE); | |
| 1873 // Classes are same, perform guarded list length check. | |
| 1874 ASSERT(field_reg != kNoRegister); | |
| 1875 ASSERT(value_cid_reg != kNoRegister); | |
| 1876 FieldAddress field_length_operand( | |
| 1877 field_reg, Field::guarded_list_length_offset()); | |
| 1878 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1879 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1880 __ ldr(value_cid_reg, | |
| 1881 FieldAddress(value_reg, Array::length_offset())); | |
| 1882 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1883 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1884 __ ldr(value_cid_reg, | |
| 1885 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1886 } | |
| 1887 __ ldr(IP, field_length_operand); | |
| 1888 __ cmp(value_cid_reg, Operand(IP)); | |
| 1889 } | |
| 1890 | |
| 1891 if (field().is_nullable() && (field_cid != kNullCid)) { | 1744 if (field().is_nullable() && (field_cid != kNullCid)) { |
| 1892 __ b(&ok, EQ); | 1745 __ b(&ok, EQ); |
| 1893 __ CompareImmediate(value_reg, | 1746 if (field_cid != kSmiCid) { |
| 1894 reinterpret_cast<intptr_t>(Object::null())); | 1747 __ CompareImmediate(value_cid_reg, kNullCid); |
| 1748 } else { |
| 1749 __ CompareImmediate(value_reg, |
| 1750 reinterpret_cast<intptr_t>(Object::null())); |
| 1751 } |
| 1895 } | 1752 } |
| 1896 __ b(fail, NE); | 1753 __ b(fail, NE); |
| 1897 } else { | 1754 } else { |
| 1898 // Both value's and field's class id is known. | 1755 // Both value's and field's class id is known. |
| 1899 if ((value_cid != field_cid) && (value_cid != nullability)) { | 1756 ASSERT((value_cid != field_cid) && (value_cid != nullability)); |
| 1900 __ b(fail); | 1757 __ b(fail); |
| 1901 } else if (field_has_length && (value_cid == field_cid)) { | |
| 1902 ASSERT(value_cid_reg != kNoRegister); | |
| 1903 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) { | |
| 1904 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1905 __ ldr(value_cid_reg, | |
| 1906 FieldAddress(value_reg, Array::length_offset())); | |
| 1907 } else if (RawObject::IsTypedDataClassId(field_cid)) { | |
| 1908 // Destroy value_cid_reg (safe because we are finished with it). | |
| 1909 __ ldr(value_cid_reg, | |
| 1910 FieldAddress(value_reg, TypedData::length_offset())); | |
| 1911 } | |
| 1912 __ CompareImmediate(value_cid_reg, field_length); | |
| 1913 __ b(fail, NE); | |
| 1914 } else { | |
| 1915 UNREACHABLE(); | |
| 1916 } | |
| 1917 } | 1758 } |
| 1918 } | 1759 } |
| 1919 __ Bind(&ok); | 1760 __ Bind(&ok); |
| 1920 } | 1761 } |
| 1921 | 1762 |
| 1922 | 1763 |
| 1764 LocationSummary* GuardFieldLengthInstr::MakeLocationSummary(Isolate* isolate, |
| 1765 bool opt) const { |
| 1766 const intptr_t kNumInputs = 1; |
| 1767 LocationSummary* summary = new(isolate) LocationSummary( |
| 1768 isolate, kNumInputs, 0, LocationSummary::kNoCall); |
| 1769 summary->set_in(0, Location::RequiresRegister()); |
| 1770 |
| 1771 if (!opt || (field().guarded_list_length() == Field::kUnknownFixedLength)) { |
| 1772 // We need temporaries for field object, length offset and expected length. |
| 1773 summary->AddTemp(Location::RequiresRegister()); |
| 1774 summary->AddTemp(Location::RequiresRegister()); |
| 1775 summary->AddTemp(Location::RequiresRegister()); |
| 1776 } else { |
| 1777 // TODO(vegorov): can use TMP when length is small enough to fit into |
| 1778 // immediate. |
| 1779 summary->AddTemp(Location::RequiresRegister()); |
| 1780 } |
| 1781 |
| 1782 return summary; |
| 1783 } |
| 1784 |
| 1785 |
| 1786 void GuardFieldLengthInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1787 if (field().guarded_list_length() == Field::kNoFixedLength) { |
| 1788 ASSERT(!compiler->is_optimizing()); |
| 1789 return; // Nothing to emit. |
| 1790 } |
| 1791 |
| 1792 Label* deopt = compiler->is_optimizing() ? |
| 1793 compiler->AddDeoptStub(deopt_id(), ICData::kDeoptGuardField) : NULL; |
| 1794 |
| 1795 const Register value_reg = locs()->in(0).reg(); |
| 1796 |
| 1797 if (!compiler->is_optimizing() || |
| 1798 (field().guarded_list_length() == Field::kUnknownFixedLength)) { |
| 1799 const Register field_reg = locs()->temp(0).reg(); |
| 1800 const Register offset_reg = locs()->temp(1).reg(); |
| 1801 const Register length_reg = locs()->temp(2).reg(); |
| 1802 |
| 1803 Label ok; |
| 1804 |
| 1805 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); |
| 1806 |
| 1807 __ ldrsb(offset_reg, FieldAddress(field_reg, |
| 1808 Field::guarded_list_length_in_object_offset_offset())); |
| 1809 __ ldr(length_reg, FieldAddress(field_reg, |
| 1810 Field::guarded_list_length_offset())); |
| 1811 |
| 1812 __ tst(offset_reg, Operand(offset_reg)); |
| 1813 __ b(&ok, MI); |
| 1814 |
| 1815 // Load the length from the value. GuardFieldClass already verified that |
| 1816 // value's class matches guarded class id of the field. |
| 1817 // offset_reg contains offset already corrected by -kHeapObjectTag that is |
| 1818 // why we use Address instead of FieldAddress. |
| 1819 __ ldr(IP, Address(value_reg, offset_reg)); |
| 1820 __ cmp(length_reg, Operand(IP)); |
| 1821 |
| 1822 if (deopt == NULL) { |
| 1823 __ b(&ok, EQ); |
| 1824 |
| 1825 __ Push(field_reg); |
| 1826 __ Push(value_reg); |
| 1827 __ CallRuntime(kUpdateFieldCidRuntimeEntry, 2); |
| 1828 __ Drop(2); // Drop the field and the value. |
| 1829 } else { |
| 1830 __ b(deopt, NE); |
| 1831 } |
| 1832 |
| 1833 __ Bind(&ok); |
| 1834 } else { |
| 1835 ASSERT(compiler->is_optimizing()); |
| 1836 ASSERT(field().guarded_list_length() >= 0); |
| 1837 ASSERT(field().guarded_list_length_in_object_offset() != |
| 1838 Field::kUnknownLengthOffset); |
| 1839 |
| 1840 const Register length_reg = locs()->temp(0).reg(); |
| 1841 |
| 1842 __ ldr(length_reg, |
| 1843 FieldAddress(value_reg, |
| 1844 field().guarded_list_length_in_object_offset())); |
| 1845 __ CompareImmediate(length_reg, |
| 1846 Smi::RawValue(field().guarded_list_length())); |
| 1847 __ b(deopt, NE); |
| 1848 } |
| 1849 } |
| 1850 |
| 1851 |
| 1923 class StoreInstanceFieldSlowPath : public SlowPathCode { | 1852 class StoreInstanceFieldSlowPath : public SlowPathCode { |
| 1924 public: | 1853 public: |
| 1925 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, | 1854 StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction, |
| 1926 const Class& cls) | 1855 const Class& cls) |
| 1927 : instruction_(instruction), cls_(cls) { } | 1856 : instruction_(instruction), cls_(cls) { } |
| 1928 | 1857 |
| 1929 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { | 1858 virtual void EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1930 __ Comment("StoreInstanceFieldSlowPath"); | 1859 __ Comment("StoreInstanceFieldSlowPath"); |
| 1931 __ Bind(entry_label()); | 1860 __ Bind(entry_label()); |
| 1932 | 1861 |
| (...skipping 4469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6402 compiler->GenerateCall(token_pos(), | 6331 compiler->GenerateCall(token_pos(), |
| 6403 &label, | 6332 &label, |
| 6404 PcDescriptors::kOther, | 6333 PcDescriptors::kOther, |
| 6405 locs()); | 6334 locs()); |
| 6406 __ Drop(ArgumentCount()); // Discard arguments. | 6335 __ Drop(ArgumentCount()); // Discard arguments. |
| 6407 } | 6336 } |
| 6408 | 6337 |
| 6409 } // namespace dart | 6338 } // namespace dart |
| 6410 | 6339 |
| 6411 #endif // defined TARGET_ARCH_ARM | 6340 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |