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

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 }
1628 1644
1629 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); 1645 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1630 1646
1631 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); 1647 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1632 FieldAddress field_nullability_operand( 1648 FieldAddress field_nullability_operand(
1633 field_reg, Field::is_nullable_offset()); 1649 field_reg, Field::is_nullable_offset());
1650 FieldAddress field_length_operand(
1651 field_reg, Field::guarded_list_length_offset());
1634 1652
1635 if (value_cid == kDynamicCid) { 1653 if (value_cid == kDynamicCid) {
1636 if (value_cid_reg == kNoRegister) { 1654 if (value_cid_reg == kNoRegister) {
1637 ASSERT(!compiler->is_optimizing()); 1655 ASSERT(!compiler->is_optimizing());
1638 value_cid_reg = EDX; 1656 value_cid_reg = EDX;
1639 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); 1657 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1640 } 1658 }
1641 1659
1642 LoadValueCid(compiler, value_cid_reg, value_reg); 1660 LoadValueCid(compiler, value_cid_reg, value_reg);
1643 1661
1662 Label skip_length_check;
1644 __ cmpl(value_cid_reg, field_cid_operand); 1663 __ cmpl(value_cid_reg, field_cid_operand);
1645 __ j(EQUAL, &ok); 1664 // Value CID != Field guard CID, skip length check.
1665 __ j(NOT_EQUAL, &skip_length_check);
1666 if (field_has_length) {
1667 // Field guard may have remembered list length, check it.
1668 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1669 __ pushl(value_cid_reg);
1670 __ movl(value_cid_reg,
1671 FieldAddress(value_reg, Array::length_offset()));
1672 __ cmpl(value_cid_reg, Immediate(field_length));
1673 __ popl(value_cid_reg);
1674 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1675 __ pushl(value_cid_reg);
1676 __ movl(value_cid_reg,
1677 FieldAddress(value_reg, TypedData::length_offset()));
1678 __ cmpl(value_cid_reg, Immediate(field_length));
1679 __ popl(value_cid_reg);
1680 } else {
1681 ASSERT(field_cid == kIllegalCid);
1682 // Following jump cannot not occur, fall through.
1683 }
1684 __ j(NOT_EQUAL, fail);
1685 }
1686 __ Bind(&skip_length_check);
1646 __ cmpl(value_cid_reg, field_nullability_operand); 1687 __ cmpl(value_cid_reg, field_nullability_operand);
1647 } else if (value_cid == kNullCid) { 1688 } else if (value_cid == kNullCid) {
1689 // Value in graph known to be null.
1690 // Compare with null.
1648 __ cmpl(field_nullability_operand, Immediate(value_cid)); 1691 __ cmpl(field_nullability_operand, Immediate(value_cid));
1649 } else { 1692 } else {
1693 // Value in graph known to be non-null.
1694 Label skip_length_check;
1695 // Compare class id with guard field class id.
1650 __ cmpl(field_cid_operand, Immediate(value_cid)); 1696 __ cmpl(field_cid_operand, Immediate(value_cid));
1697 // If not equal, skip over length check.
1698 __ j(NOT_EQUAL, &skip_length_check);
1699 // Insert length check.
1700 if (field_has_length) {
1701 if (value_cid_reg == kNoRegister) {
1702 ASSERT(!compiler->is_optimizing());
1703 value_cid_reg = EDX;
1704 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1705 }
1706 ASSERT(value_cid_reg != kNoRegister);
1707 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1708 __ pushl(value_cid_reg);
1709 __ movl(value_cid_reg,
1710 FieldAddress(value_reg, Array::length_offset()));
1711 __ cmpl(value_cid_reg, Immediate(field_length));
1712 __ popl(value_cid_reg);
1713 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1714 __ pushl(value_cid_reg);
1715 __ movl(value_cid_reg,
1716 FieldAddress(value_reg, TypedData::length_offset()));
1717 __ cmpl(value_cid_reg, Immediate(field_length));
1718 __ popl(value_cid_reg);
1719 } else {
1720 ASSERT(field_cid == kIllegalCid);
1721 // Following jump cannot not occur, fall through.
1722 }
1723 }
1724 // Not identical, possibly null.
1725 __ Bind(&skip_length_check);
1651 } 1726 }
1727 // Jump when class id guard and list length guard are okay.
1652 __ j(EQUAL, &ok); 1728 __ j(EQUAL, &ok);
1653 1729
1730
1731 // Check if guard field is uninitialized.
1654 __ cmpl(field_cid_operand, Immediate(kIllegalCid)); 1732 __ cmpl(field_cid_operand, Immediate(kIllegalCid));
1733 // Jump to failure path when guard field has been initialized and
1734 // the field and value class ids do not not match.
1655 __ j(NOT_EQUAL, fail); 1735 __ j(NOT_EQUAL, fail);
1656 1736
1737 // At this point the field guard is being initialized for the first time.
1657 if (value_cid == kDynamicCid) { 1738 if (value_cid == kDynamicCid) {
1739 // Do not know value's class id.
1658 __ movl(field_cid_operand, value_cid_reg); 1740 __ movl(field_cid_operand, value_cid_reg);
1659 __ movl(field_nullability_operand, value_cid_reg); 1741 __ movl(field_nullability_operand, value_cid_reg);
1742 if (field_has_length) {
1743 Label check_array, local_exit, local_fail;
1744 __ cmpl(value_cid_reg, Immediate(kNullCid));
1745 __ j(EQUAL, &local_fail);
1746 // Check for typed data array.
1747 __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
1748 __ j(GREATER, &local_fail); // Not a typed array or a regular array.
1749 __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
1750 __ j(LESS, &check_array); // Could still be a regular array.
1751 // Destroy value_cid_reg (safe because we are finished with it).
1752 __ movl(value_cid_reg,
1753 FieldAddress(value_reg, TypedData::length_offset()));
1754 __ movl(field_length_operand, value_cid_reg);
1755 __ jmp(&local_exit); // Updated field length typed data array.
1756 // Check for regular array.
1757 __ Bind(&check_array);
1758 __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
1759 __ j(GREATER, &local_fail);
1760 __ cmpl(value_cid_reg, Immediate(kArrayCid));
1761 __ j(LESS, &local_fail);
1762 // Destroy value_cid_reg (safe because we are finished with it).
1763 __ movl(value_cid_reg,
1764 FieldAddress(value_reg, Array::length_offset()));
1765 __ movl(field_length_operand, value_cid_reg);
1766 __ jmp(&local_exit); // Updated field length from regular array.
1767
1768 __ Bind(&local_fail);
1769 __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
1770
1771 __ Bind(&local_exit);
1772 }
1660 } else { 1773 } else {
1774 if (value_cid_reg == kNoRegister) {
1775 ASSERT(!compiler->is_optimizing());
1776 value_cid_reg = EDX;
1777 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1778 }
1779 ASSERT(value_cid_reg != kNoRegister);
1780 ASSERT(field_reg != kNoRegister);
1661 __ movl(field_cid_operand, Immediate(value_cid)); 1781 __ movl(field_cid_operand, Immediate(value_cid));
1662 __ movl(field_nullability_operand, Immediate(value_cid)); 1782 __ movl(field_nullability_operand, Immediate(value_cid));
1783 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
1784 // Destroy value_cid_reg (safe because we are finished with it).
1785 __ movl(value_cid_reg,
1786 FieldAddress(value_reg, Array::length_offset()));
1787 __ movl(field_length_operand, value_cid_reg);
1788 } else if (RawObject::IsTypedDataClassId(value_cid)) {
1789 // Destroy value_cid_reg (safe because we are finished with it).
1790 __ movl(value_cid_reg,
1791 FieldAddress(value_reg, TypedData::length_offset()));
1792 __ movl(field_length_operand, value_cid_reg);
1793 } else {
1794 __ movl(field_length_operand, Immediate(Field::kNoFixedLength));
1795 }
1663 } 1796 }
1664 1797
1665 if (!ok_is_fall_through) { 1798 if (!ok_is_fall_through) {
1666 __ jmp(&ok); 1799 __ jmp(&ok);
1667 } 1800 }
1668 } else { 1801 } else {
1802 // Field guard class has been initialized and is known.
1803
1804 if (field_reg != kNoRegister) {
1805 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1806 }
1807
1669 if (value_cid == kDynamicCid) { 1808 if (value_cid == kDynamicCid) {
1670 // Field's guarded class id is fixed by value's class id is not known. 1809 // Value's class id is not known.
1671 __ testl(value_reg, Immediate(kSmiTagMask)); 1810 __ testl(value_reg, Immediate(kSmiTagMask));
1672 1811
1673 if (field_cid != kSmiCid) { 1812 if (field_cid != kSmiCid) {
1674 __ j(ZERO, fail); 1813 __ j(ZERO, fail);
1675 __ LoadClassId(value_cid_reg, value_reg); 1814 __ LoadClassId(value_cid_reg, value_reg);
1676 __ cmpl(value_cid_reg, Immediate(field_cid)); 1815 __ cmpl(value_cid_reg, Immediate(field_cid));
1677 } 1816 }
1678 1817
1818 if (field_has_length) {
1819 // Jump when Value CID != Field guard CID
1820 __ j(NOT_EQUAL, fail);
1821
1822 // Classes are same, perform guarded list length check.
1823 ASSERT(field_reg != kNoRegister);
1824 ASSERT(value_cid_reg != kNoRegister);
1825 FieldAddress field_length_operand(
1826 field_reg, Field::guarded_list_length_offset());
1827 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1828 // Destroy value_cid_reg (safe because we are finished with it).
1829 __ movl(value_cid_reg,
1830 FieldAddress(value_reg, Array::length_offset()));
1831 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1832 // Destroy value_cid_reg (safe because we are finished with it).
1833 __ movl(value_cid_reg,
1834 FieldAddress(value_reg, TypedData::length_offset()));
1835 }
1836 __ cmpl(value_cid_reg, field_length_operand);
1837 }
1838
1679 if (field().is_nullable() && (field_cid != kNullCid)) { 1839 if (field().is_nullable() && (field_cid != kNullCid)) {
1680 __ j(EQUAL, &ok); 1840 __ j(EQUAL, &ok);
1681 const Immediate& raw_null = 1841 const Immediate& raw_null =
1682 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1842 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1683 __ cmpl(value_reg, raw_null); 1843 __ cmpl(value_reg, raw_null);
1684 } 1844 }
1685 1845
1686 if (ok_is_fall_through) { 1846 if (ok_is_fall_through) {
1687 __ j(NOT_EQUAL, fail); 1847 __ j(NOT_EQUAL, fail);
1688 } else { 1848 } else {
1689 __ j(EQUAL, &ok); 1849 __ j(EQUAL, &ok);
1690 } 1850 }
1691 } else { 1851 } else {
1692 // Both value's and field's class id is known. 1852 // Both value's and field's class id is known.
1693 if ((value_cid != field_cid) && (value_cid != nullability)) { 1853 if ((value_cid != field_cid) && (value_cid != nullability)) {
1694 if (ok_is_fall_through) { 1854 if (ok_is_fall_through) {
1695 __ jmp(fail); 1855 __ jmp(fail);
1696 } 1856 }
1857 } else if (field_has_length && (value_cid == field_cid)) {
1858 ASSERT(value_cid_reg != kNoRegister);
1859 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1860 // Destroy value_cid_reg (safe because we are finished with it).
1861 __ movl(value_cid_reg,
1862 FieldAddress(value_reg, Array::length_offset()));
1863 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1864 // Destroy value_cid_reg (safe because we are finished with it).
1865 __ movl(value_cid_reg,
1866 FieldAddress(value_reg, TypedData::length_offset()));
1867 }
1868 __ cmpl(value_cid_reg, Immediate(field_length));
1869 if (ok_is_fall_through) {
1870 __ j(NOT_EQUAL, fail);
1871 }
1697 } else { 1872 } else {
1698 // Nothing to emit. 1873 // Nothing to emit.
1699 ASSERT(!compiler->is_optimizing()); 1874 ASSERT(!compiler->is_optimizing());
1700 return; 1875 return;
1701 } 1876 }
1702 } 1877 }
1703 } 1878 }
1704 1879
1705 if (deopt == NULL) { 1880 if (deopt == NULL) {
1706 ASSERT(!compiler->is_optimizing()); 1881 ASSERT(!compiler->is_optimizing());
(...skipping 3277 matching lines...) Expand 10 before | Expand all | Expand 10 after
4984 PcDescriptors::kOther, 5159 PcDescriptors::kOther,
4985 locs()); 5160 locs());
4986 __ Drop(2); // Discard type arguments and receiver. 5161 __ Drop(2); // Discard type arguments and receiver.
4987 } 5162 }
4988 5163
4989 } // namespace dart 5164 } // namespace dart
4990 5165
4991 #undef __ 5166 #undef __
4992 5167
4993 #endif // defined TARGET_ARCH_IA32 5168 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698