Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(265)

Side by Side Diff: runtime/vm/intermediate_language_ia32.cc

Issue 22851003: Initial support for length guards on final fields. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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_IA32. 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
6 #if defined(TARGET_ARCH_IA32) 6 #if defined(TARGET_ARCH_IA32)
7 7
8 #include "vm/intermediate_language.h" 8 #include "vm/intermediate_language.h"
9 9
10 #include "vm/dart_entry.h" 10 #include "vm/dart_entry.h"
(...skipping 1559 matching lines...) Expand 10 before | Expand all | Expand 10 after
1570 UNREACHABLE(); 1570 UNREACHABLE();
1571 } 1571 }
1572 } 1572 }
1573 1573
1574 1574
1575 LocationSummary* GuardFieldInstr::MakeLocationSummary() const { 1575 LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
1576 const intptr_t kNumInputs = 1; 1576 const intptr_t kNumInputs = 1;
1577 LocationSummary* summary = 1577 LocationSummary* summary =
1578 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); 1578 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
1579 summary->set_in(0, Location::RequiresRegister()); 1579 summary->set_in(0, Location::RequiresRegister());
1580 if ((value()->Type()->ToCid() == kDynamicCid) && 1580 const bool field_has_length = field().needs_length_check();
1581 (field().guarded_cid() != kSmiCid)) { 1581 const bool need_value_temp_reg =
1582 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
1583 (field().guarded_cid() != kSmiCid)));
1584 if (need_value_temp_reg) {
1582 summary->AddTemp(Location::RequiresRegister()); 1585 summary->AddTemp(Location::RequiresRegister());
1583 } 1586 }
1584 if (field().guarded_cid() == kIllegalCid) { 1587 const bool need_field_temp_reg =
1588 field_has_length || (field().guarded_cid() == kIllegalCid);
1589 if (need_field_temp_reg) {
1585 summary->AddTemp(Location::RequiresRegister()); 1590 summary->AddTemp(Location::RequiresRegister());
1586 } 1591 }
1587 return summary; 1592 return summary;
1588 } 1593 }
1589 1594
1590 1595
1591 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 1596 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1592 const intptr_t field_cid = field().guarded_cid(); 1597 const intptr_t field_cid = field().guarded_cid();
1593 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; 1598 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
1599 const intptr_t field_length = field().guarded_list_length();
1600 const bool field_has_length = field().needs_length_check();
1601 const bool needs_value_temp_reg =
1602 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
1603 (field().guarded_cid() != kSmiCid)));
1604 const bool needs_field_temp_reg =
1605 field_has_length || (field().guarded_cid() == kIllegalCid);
1606 if (field_has_length) {
1607 // Currently, we should only see final fields that remember length.
1608 ASSERT(field().is_final());
1609 }
1594 1610
1595 if (field_cid == kDynamicCid) { 1611 if (field_cid == kDynamicCid) {
1596 ASSERT(!compiler->is_optimizing()); 1612 ASSERT(!compiler->is_optimizing());
1597 return; // Nothing to emit. 1613 return; // Nothing to emit.
1598 } 1614 }
1599 1615
1600 const intptr_t value_cid = value()->Type()->ToCid(); 1616 const intptr_t value_cid = value()->Type()->ToCid();
1601 1617
1602 Register value_reg = locs()->in(0).reg(); 1618 Register value_reg = locs()->in(0).reg();
1603 1619
1604 Register value_cid_reg = ((value_cid == kDynamicCid) && 1620 Register value_cid_reg = needs_value_temp_reg ?
1605 (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister; 1621 locs()->temp(0).reg() : kNoRegister;
1606 1622
1607 Register field_reg = (field_cid == kIllegalCid) ? 1623 Register field_reg = needs_field_temp_reg ?
1608 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; 1624 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
1609 1625
1610 Label ok, fail_label; 1626 Label ok, fail_label;
1611 1627
1612 Label* deopt = compiler->is_optimizing() ? 1628 Label* deopt = compiler->is_optimizing() ?
1613 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL; 1629 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
1614 1630
1615 Label* fail = (deopt != NULL) ? deopt : &fail_label; 1631 Label* fail = (deopt != NULL) ? deopt : &fail_label;
1616 1632
1617 const bool ok_is_fall_through = (deopt != NULL); 1633 const bool ok_is_fall_through = (deopt != NULL);
1618 1634
1619 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { 1635 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
1620 if (!compiler->is_optimizing()) { 1636 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
1621 // Currently we can't have different location summaries for optimized 1637 // Currently we can't have different location summaries for optimized
1622 // and non-optimized code. So instead we manually pick up a register 1638 // and non-optimized code. So instead we manually pick up a register
1623 // that is known to be free because we know how non-optimizing compiler 1639 // that is known to be free because we know how non-optimizing compiler
1624 // allocates registers. 1640 // allocates registers.
1625 field_reg = EBX; 1641 field_reg = EBX;
1626 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); 1642 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
1627 } 1643 }
1644 // Non-optimizing compiler or an uninitialized field guard data.
1628 1645
1629 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); 1646 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1630 1647
1631 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); 1648 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1632 FieldAddress field_nullability_operand( 1649 FieldAddress field_nullability_operand(
1633 field_reg, Field::is_nullable_offset()); 1650 field_reg, Field::is_nullable_offset());
1651 FieldAddress field_length_operand(
1652 field_reg, Field::guarded_list_length_offset());
1634 1653
1635 if (value_cid == kDynamicCid) { 1654 if (value_cid == kDynamicCid) {
1655 // Value has unknown class id.
1636 if (value_cid_reg == kNoRegister) { 1656 if (value_cid_reg == kNoRegister) {
1637 ASSERT(!compiler->is_optimizing()); 1657 ASSERT(!compiler->is_optimizing());
1638 value_cid_reg = EDX; 1658 value_cid_reg = EDX;
1639 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); 1659 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1640 } 1660 }
1641
1642 LoadValueCid(compiler, value_cid_reg, value_reg); 1661 LoadValueCid(compiler, value_cid_reg, value_reg);
1643 1662
1663 Label skip_length_check;
1644 __ cmpl(value_cid_reg, field_cid_operand); 1664 __ cmpl(value_cid_reg, field_cid_operand);
1645 __ j(EQUAL, &ok); 1665 // Value CID != Field guard CID, skip length check.
1666 __ j(NOT_EQUAL, &skip_length_check);
1667 if (field_has_length) {
1668 // Field guard may have remembered list length, check it.
1669 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1670 __ pushl(value_cid_reg);
1671 __ movl(value_cid_reg,
1672 FieldAddress(value_reg, Array::length_offset()));
1673 __ cmpl(value_cid_reg, Immediate(field_length));
1674 __ popl(value_cid_reg);
1675 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1676 __ pushl(value_cid_reg);
1677 __ movl(value_cid_reg,
1678 FieldAddress(value_reg, TypedData::length_offset()));
1679 __ cmpl(value_cid_reg, Immediate(field_length));
1680 __ popl(value_cid_reg);
1681 } else {
1682 ASSERT(field_cid == kIllegalCid);
1683 // Following jump cannot not occur, fall through.
1684 }
1685 __ j(NOT_EQUAL, fail);
1686 }
1687 __ Bind(&skip_length_check);
1646 __ cmpl(value_cid_reg, field_nullability_operand); 1688 __ cmpl(value_cid_reg, field_nullability_operand);
1647 } else if (value_cid == kNullCid) { 1689 } else if (value_cid == kNullCid) {
1690 // Value in graph known to be null.
1691 // Compare with null.
1648 __ cmpl(field_nullability_operand, Immediate(value_cid)); 1692 __ cmpl(field_nullability_operand, Immediate(value_cid));
1649 } else { 1693 } else {
1694 // Value in graph known to be non-null.
1695 Label skip_length_check;
1696 // Compare class id with guard field class id.
1650 __ cmpl(field_cid_operand, Immediate(value_cid)); 1697 __ cmpl(field_cid_operand, Immediate(value_cid));
1651 } 1698 // If not equal, skip over length check.
1699 __ j(NOT_EQUAL, &skip_length_check);
1700 // Insert length check.
1701 if (field_has_length) {
1702 if (value_cid_reg == kNoRegister) {
1703 ASSERT(!compiler->is_optimizing());
1704 value_cid_reg = EDX;
1705 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1706 }
1707 ASSERT(value_cid_reg != kNoRegister);
1708 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1709 __ pushl(value_cid_reg);
1710 __ movl(value_cid_reg,
1711 FieldAddress(value_reg, Array::length_offset()));
1712 __ cmpl(value_cid_reg, Immediate(field_length));
1713 __ popl(value_cid_reg);
1714 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1715 __ pushl(value_cid_reg);
1716 __ movl(value_cid_reg,
1717 FieldAddress(value_reg, TypedData::length_offset()));
1718 __ cmpl(value_cid_reg, Immediate(field_length));
1719 __ popl(value_cid_reg);
1720 } else {
1721 ASSERT(field_cid == kIllegalCid);
1722 // Following jump cannot not occur, fall through.
1723 }
1724 }
1725 // Not identical, possibly null.
1726 __ Bind(&skip_length_check);
1727 }
1728 // Jump when class id guard and list length guard are okay.
1652 __ j(EQUAL, &ok); 1729 __ j(EQUAL, &ok);
1653 1730
1731
1732 // Check if guard field is uninitialized.
1654 __ cmpl(field_cid_operand, Immediate(kIllegalCid)); 1733 __ cmpl(field_cid_operand, Immediate(kIllegalCid));
1734 // Jump to failure path when guard field has been initialized and
1735 // the field and value class ids do not not match.
1655 __ j(NOT_EQUAL, fail); 1736 __ j(NOT_EQUAL, fail);
1656 1737
1738 // At this point the field guard is being initialized for the first time.
1657 if (value_cid == kDynamicCid) { 1739 if (value_cid == kDynamicCid) {
1740 // Do not know value's class id.
1658 __ movl(field_cid_operand, value_cid_reg); 1741 __ movl(field_cid_operand, value_cid_reg);
1659 __ movl(field_nullability_operand, value_cid_reg); 1742 __ movl(field_nullability_operand, value_cid_reg);
1743 if (field_has_length) {
1744 Label check_array, local_exit, local_fail;
1745 __ cmpl(value_cid_reg, Immediate(kNullCid));
1746 __ j(EQUAL, &local_fail);
1747 // Check for typed data array.
1748 __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
1749 __ j(GREATER, &local_fail); // Not a typed array or a regular array.
1750 __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
1751 __ j(LESS, &check_array); // Could still be a regular array.
1752 // Destroy value_cid_reg (safe because we are finished with it).
1753 __ movl(value_cid_reg,
1754 FieldAddress(value_reg, TypedData::length_offset()));
1755 __ movl(field_length_operand, value_cid_reg);
1756 __ jmp(&local_exit); // Updated field length typed data array.
1757 // Check for regular array.
1758 __ Bind(&check_array);
1759 __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
1760 __ j(GREATER, &local_fail);
1761 __ cmpl(value_cid_reg, Immediate(kArrayCid));
1762 __ j(LESS, &local_fail);
1763 // Destroy value_cid_reg (safe because we are finished with it).
1764 __ movl(value_cid_reg,
1765 FieldAddress(value_reg, Array::length_offset()));
1766 __ movl(field_length_operand, value_cid_reg);
1767 __ jmp(&local_exit); // Updated field length from regular array.
1768
1769 __ Bind(&local_fail);
1770 __ movl(field_length_operand, Immediate(Field::kNoLength));
1771
1772 __ Bind(&local_exit);
1773 }
1660 } else { 1774 } else {
1775 if (value_cid_reg == kNoRegister) {
1776 ASSERT(!compiler->is_optimizing());
1777 value_cid_reg = EDX;
1778 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1779 }
1780 ASSERT(value_cid_reg != kNoRegister);
1781 ASSERT(field_reg != kNoRegister);
1661 __ movl(field_cid_operand, Immediate(value_cid)); 1782 __ movl(field_cid_operand, Immediate(value_cid));
1662 __ movl(field_nullability_operand, Immediate(value_cid)); 1783 __ movl(field_nullability_operand, Immediate(value_cid));
1784 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
1785 // Destroy value_cid_reg (safe because we are finished with it).
1786 __ movl(value_cid_reg,
1787 FieldAddress(value_reg, Array::length_offset()));
1788 __ movl(field_length_operand, value_cid_reg);
1789 } else if (RawObject::IsTypedDataClassId(value_cid)) {
1790 // Destroy value_cid_reg (safe because we are finished with it).
1791 __ movl(value_cid_reg,
1792 FieldAddress(value_reg, TypedData::length_offset()));
1793 __ movl(field_length_operand, value_cid_reg);
1794 } else {
1795 __ movl(field_length_operand, Immediate(Field::kNoLength));
1796 }
1663 } 1797 }
1664 1798
1665 if (!ok_is_fall_through) { 1799 if (!ok_is_fall_through) {
1666 __ jmp(&ok); 1800 __ jmp(&ok);
1667 } 1801 }
1668 } else { 1802 } else {
1803 // Field guard class has been initialized and is known.
1804
1805 if (field_reg != kNoRegister) {
1806 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1807 }
1808
1669 if (value_cid == kDynamicCid) { 1809 if (value_cid == kDynamicCid) {
1670 // Field's guarded class id is fixed by value's class id is not known. 1810 // Value's class id is not known.
1671 __ testl(value_reg, Immediate(kSmiTagMask)); 1811 __ testl(value_reg, Immediate(kSmiTagMask));
1672 1812
1673 if (field_cid != kSmiCid) { 1813 if (field_cid != kSmiCid) {
1814 // value is a smi.
1674 __ j(ZERO, fail); 1815 __ j(ZERO, fail);
1675 __ LoadClassId(value_cid_reg, value_reg); 1816 __ LoadClassId(value_cid_reg, value_reg);
1676 __ cmpl(value_cid_reg, Immediate(field_cid)); 1817 __ cmpl(value_cid_reg, Immediate(field_cid));
1677 } 1818 }
1678 1819
1820 if (field_has_length) {
1821 // Jump when Value CID != Field guard CID
1822 __ j(NOT_EQUAL, fail);
1823
1824 // Classes are same, perform guarded list length check.
1825 ASSERT(field_reg != kNoRegister);
1826 ASSERT(value_cid_reg != kNoRegister);
1827 FieldAddress field_length_operand(
1828 field_reg, Field::guarded_list_length_offset());
1829 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1830 // Destroy value_cid_reg (safe because we are finished with it).
1831 __ movl(value_cid_reg,
1832 FieldAddress(value_reg, Array::length_offset()));
1833 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1834 // Destroy value_cid_reg (safe because we are finished with it).
1835 __ movl(value_cid_reg,
1836 FieldAddress(value_reg, TypedData::length_offset()));
1837 }
1838 __ cmpl(value_cid_reg, field_length_operand);
1839 }
1840
1679 if (field().is_nullable() && (field_cid != kNullCid)) { 1841 if (field().is_nullable() && (field_cid != kNullCid)) {
1680 __ j(EQUAL, &ok); 1842 __ j(EQUAL, &ok);
1681 const Immediate& raw_null = 1843 const Immediate& raw_null =
1682 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1844 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1683 __ cmpl(value_reg, raw_null); 1845 __ cmpl(value_reg, raw_null);
1684 } 1846 }
1685 1847
1686 if (ok_is_fall_through) { 1848 if (ok_is_fall_through) {
1687 __ j(NOT_EQUAL, fail); 1849 __ j(NOT_EQUAL, fail);
1688 } else { 1850 } else {
1689 __ j(EQUAL, &ok); 1851 __ j(EQUAL, &ok);
1690 } 1852 }
1691 } else { 1853 } else {
1692 // Both value's and field's class id is known. 1854 // Both value's and field's class id is known.
1693 if ((value_cid != field_cid) && (value_cid != nullability)) { 1855 if ((value_cid != field_cid) && (value_cid != nullability)) {
1694 if (ok_is_fall_through) { 1856 if (ok_is_fall_through) {
1695 __ jmp(fail); 1857 __ jmp(fail);
1696 } 1858 }
1859 } else if (field_has_length && (value_cid == field_cid)) {
1860 ASSERT(value_cid_reg != kNoRegister);
1861 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1862 // Destroy value_cid_reg (safe because we are finished with it).
1863 __ movl(value_cid_reg,
1864 FieldAddress(value_reg, Array::length_offset()));
1865 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1866 // Destroy value_cid_reg (safe because we are finished with it).
1867 __ movl(value_cid_reg,
1868 FieldAddress(value_reg, TypedData::length_offset()));
1869 }
1870 __ cmpl(value_cid_reg, Immediate(field_length));
1871 if (ok_is_fall_through) {
1872 __ j(NOT_EQUAL, fail);
1873 }
1697 } else { 1874 } else {
1698 // Nothing to emit. 1875 // Nothing to emit.
1699 ASSERT(!compiler->is_optimizing()); 1876 ASSERT(!compiler->is_optimizing());
1700 return; 1877 return;
1701 } 1878 }
1702 } 1879 }
1703 } 1880 }
1704 1881
1705 if (deopt == NULL) { 1882 if (deopt == NULL) {
1706 ASSERT(!compiler->is_optimizing()); 1883 ASSERT(!compiler->is_optimizing());
(...skipping 3271 matching lines...) Expand 10 before | Expand all | Expand 10 after
4978 PcDescriptors::kOther, 5155 PcDescriptors::kOther,
4979 locs()); 5156 locs());
4980 __ Drop(2); // Discard type arguments and receiver. 5157 __ Drop(2); // Discard type arguments and receiver.
4981 } 5158 }
4982 5159
4983 } // namespace dart 5160 } // namespace dart
4984 5161
4985 #undef __ 5162 #undef __
4986 5163
4987 #endif // defined TARGET_ARCH_IA32 5164 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698