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

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 intptr_t field_length = field().guarded_list_length();
1581 (field().guarded_cid() != kSmiCid)) { 1581 const bool field_has_length = field_length >= Field::kUnknownLength;
srdjan 2013/08/14 17:01:08 You can move this 'intelligence' into class Field:
Cutch 2013/08/15 16:39:12 Done.
1582 const bool need_value_temp_reg =
srdjan 2013/08/14 17:01:08 Maybe assert that only final fields have length. T
Cutch 2013/08/15 16:39:12 The Field::needs_length_check function now include
1583 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
1584 (field().guarded_cid() != kSmiCid)));
1585 if (need_value_temp_reg) {
1582 summary->AddTemp(Location::RequiresRegister()); 1586 summary->AddTemp(Location::RequiresRegister());
1583 } 1587 }
1584 if (field().guarded_cid() == kIllegalCid) { 1588 const bool need_field_temp_reg =
1589 field_has_length || (field().guarded_cid() == kIllegalCid);
1590 if (need_field_temp_reg) {
1585 summary->AddTemp(Location::RequiresRegister()); 1591 summary->AddTemp(Location::RequiresRegister());
1586 } 1592 }
1587 return summary; 1593 return summary;
1588 } 1594 }
1589 1595
1590 1596
1591 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { 1597 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
1592 const intptr_t field_cid = field().guarded_cid(); 1598 const intptr_t field_cid = field().guarded_cid();
1593 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; 1599 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid;
1600 const intptr_t field_length = field().guarded_list_length();
1601 const bool field_has_length = field_length >= Field::kUnknownLength;
1602 const bool need_value_temp_reg =
srdjan 2013/08/14 17:01:08 s/need_value_temp_reg/needs_value_temp_reg/ ?
Cutch 2013/08/15 16:39:12 Done.
1603 (field_has_length || ((value()->Type()->ToCid() == kDynamicCid) &&
1604 (field().guarded_cid() != kSmiCid)));
1605 const bool need_field_temp_reg =
srdjan 2013/08/14 17:01:08 ditto ?
Cutch 2013/08/15 16:39:12 Done.
1606 field_has_length || (field().guarded_cid() == kIllegalCid);
1607 if (field_has_length) {
1608 // Currently, we should only see final fields that remember length.
1609 ASSERT(field().is_final());
1610 }
1594 1611
1595 if (field_cid == kDynamicCid) { 1612 if (field_cid == kDynamicCid) {
1596 ASSERT(!compiler->is_optimizing()); 1613 ASSERT(!compiler->is_optimizing());
1597 return; // Nothing to emit. 1614 return; // Nothing to emit.
1598 } 1615 }
1599 1616
1600 const intptr_t value_cid = value()->Type()->ToCid(); 1617 const intptr_t value_cid = value()->Type()->ToCid();
1601 1618
1602 Register value_reg = locs()->in(0).reg(); 1619 Register value_reg = locs()->in(0).reg();
1603 1620
1604 Register value_cid_reg = ((value_cid == kDynamicCid) && 1621 Register value_cid_reg = need_value_temp_reg ?
1605 (field_cid != kSmiCid)) ? locs()->temp(0).reg() : kNoRegister; 1622 locs()->temp(0).reg() : kNoRegister;
1606 1623
1607 Register field_reg = (field_cid == kIllegalCid) ? 1624 Register field_reg = need_field_temp_reg ?
1608 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister; 1625 locs()->temp(locs()->temp_count() - 1).reg() : kNoRegister;
1609 1626
1610 Label ok, fail_label; 1627 Label ok, fail_label;
1611 1628
1612 Label* deopt = compiler->is_optimizing() ? 1629 Label* deopt = compiler->is_optimizing() ?
1613 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL; 1630 compiler->AddDeoptStub(deopt_id(), kDeoptGuardField) : NULL;
1614 1631
1615 Label* fail = (deopt != NULL) ? deopt : &fail_label; 1632 Label* fail = (deopt != NULL) ? deopt : &fail_label;
1616 1633
1617 const bool ok_is_fall_through = (deopt != NULL); 1634 const bool ok_is_fall_through = (deopt != NULL);
1618 1635
1619 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) { 1636 if (!compiler->is_optimizing() || (field_cid == kIllegalCid)) {
1620 if (!compiler->is_optimizing()) { 1637 if (!compiler->is_optimizing() && (field_reg == kNoRegister)) {
1621 // Currently we can't have different location summaries for optimized 1638 // Currently we can't have different location summaries for optimized
1622 // and non-optimized code. So instead we manually pick up a register 1639 // 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 1640 // that is known to be free because we know how non-optimizing compiler
1624 // allocates registers. 1641 // allocates registers.
1625 field_reg = EBX; 1642 field_reg = EBX;
1626 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg)); 1643 ASSERT((field_reg != value_reg) && (field_reg != value_cid_reg));
1627 } 1644 }
1645 // Non-optimizing compiler or an uninitialized field guard data.
1628 1646
1629 __ LoadObject(field_reg, Field::ZoneHandle(field().raw())); 1647 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1630 1648
1631 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset()); 1649 FieldAddress field_cid_operand(field_reg, Field::guarded_cid_offset());
1632 FieldAddress field_nullability_operand( 1650 FieldAddress field_nullability_operand(
1633 field_reg, Field::is_nullable_offset()); 1651 field_reg, Field::is_nullable_offset());
1652 FieldAddress field_length_operand(
1653 field_reg, Field::guarded_list_length_offset());
1634 1654
1635 if (value_cid == kDynamicCid) { 1655 if (value_cid == kDynamicCid) {
1656 // Value has unknown class id.
1636 if (value_cid_reg == kNoRegister) { 1657 if (value_cid_reg == kNoRegister) {
1637 ASSERT(!compiler->is_optimizing()); 1658 ASSERT(!compiler->is_optimizing());
1638 value_cid_reg = EDX; 1659 value_cid_reg = EDX;
1639 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg)); 1660 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1640 } 1661 }
1641
1642 LoadValueCid(compiler, value_cid_reg, value_reg); 1662 LoadValueCid(compiler, value_cid_reg, value_reg);
1643 1663
1664 Label skip_length_check;
1644 __ cmpl(value_cid_reg, field_cid_operand); 1665 __ cmpl(value_cid_reg, field_cid_operand);
1645 __ j(EQUAL, &ok); 1666 // Value CID != Field guard CID, skip length check.
1667 __ j(NOT_EQUAL, &skip_length_check);
1668 if (field_has_length) {
1669 // Field guard may have remembered list length, checked it.
srdjan 2013/08/14 17:01:08 s/checked/check/
Cutch 2013/08/15 16:39:12 Done.
1670 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1671 __ pushl(value_cid_reg);
1672 __ movl(value_cid_reg,
1673 FieldAddress(value_reg, Array::length_offset()));
1674 __ cmpl(value_cid_reg, Immediate(field_length));
1675 __ popl(value_cid_reg);
1676 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1677 __ pushl(value_cid_reg);
1678 __ movl(value_cid_reg,
1679 FieldAddress(value_reg, TypedData::length_offset()));
1680 __ cmpl(value_cid_reg, Immediate(field_length));
1681 __ popl(value_cid_reg);
1682 }
srdjan 2013/08/14 17:01:08 else ?
Cutch 2013/08/15 16:39:12 Good catch.
1683 __ j(NOT_EQUAL, fail);
1684 }
1685 __ Bind(&skip_length_check);
1646 __ cmpl(value_cid_reg, field_nullability_operand); 1686 __ cmpl(value_cid_reg, field_nullability_operand);
1647 } else if (value_cid == kNullCid) { 1687 } else if (value_cid == kNullCid) {
1688 // Value in graph known to be null.
1689 // Compare with null.
1648 __ cmpl(field_nullability_operand, Immediate(value_cid)); 1690 __ cmpl(field_nullability_operand, Immediate(value_cid));
1649 } else { 1691 } else {
1692 // Value in graph known to be non-null.
1693 Label skip_length_check;
1694 // Compare class id with guard field class id.
1650 __ cmpl(field_cid_operand, Immediate(value_cid)); 1695 __ cmpl(field_cid_operand, Immediate(value_cid));
1696 // If not equal, skip over length check.
1697 __ j(NOT_EQUAL, &skip_length_check);
1698 // Insert length check.
1699 if (field_has_length) {
1700 if (value_cid_reg == kNoRegister) {
1701 ASSERT(!compiler->is_optimizing());
1702 value_cid_reg = EDX;
1703 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1704 }
1705 ASSERT(value_cid_reg != kNoRegister);
1706 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1707 __ pushl(value_cid_reg);
1708 __ movl(value_cid_reg,
1709 FieldAddress(value_reg, Array::length_offset()));
1710 __ cmpl(value_cid_reg, Immediate(field_length));
1711 __ popl(value_cid_reg);
1712 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1713 __ pushl(value_cid_reg);
1714 __ movl(value_cid_reg,
1715 FieldAddress(value_reg, TypedData::length_offset()));
1716 __ cmpl(value_cid_reg, Immediate(field_length));
1717 __ popl(value_cid_reg);
1718 }
srdjan 2013/08/14 17:01:08 else ?
1719 }
1720 // Not identical, possibly null.
1721 __ Bind(&skip_length_check);
1651 } 1722 }
1723 // Jump when class id guard and list length guard are okay.
1652 __ j(EQUAL, &ok); 1724 __ j(EQUAL, &ok);
1653 1725
1726
1727 // Check if guard field is uninitialized.
1654 __ cmpl(field_cid_operand, Immediate(kIllegalCid)); 1728 __ cmpl(field_cid_operand, Immediate(kIllegalCid));
1729 // Jump to failure path when guard field has been initialized and
1730 // the field and value class ids do not not match.
1655 __ j(NOT_EQUAL, fail); 1731 __ j(NOT_EQUAL, fail);
1656 1732
1733 // At this point the field guard is being initialized for the first time.
1657 if (value_cid == kDynamicCid) { 1734 if (value_cid == kDynamicCid) {
srdjan 2013/08/14 17:01:08 Maybe do not emit extra code if field is not final
Cutch 2013/08/15 16:39:12 Done.
1735 // Do not know value's class id.
1736 Label check_array, local_exit, local_fail;
1658 __ movl(field_cid_operand, value_cid_reg); 1737 __ movl(field_cid_operand, value_cid_reg);
1659 __ movl(field_nullability_operand, value_cid_reg); 1738 __ movl(field_nullability_operand, value_cid_reg);
1739 __ cmpl(value_cid_reg, Immediate(kNullCid));
1740 __ j(EQUAL, &local_fail);
1741 // Check for typed data array.
1742 __ cmpl(value_cid_reg, Immediate(kTypedDataFloat32x4ArrayCid));
1743 __ j(GREATER, &local_fail); // Not a typed array or a regular array.
1744 __ cmpl(value_cid_reg, Immediate(kTypedDataInt8ArrayCid));
1745 __ j(LESS, &check_array); // Could still be a regular array.
1746 // Destroy value_cid_reg (safe because we are finished with it).
1747 __ movl(value_cid_reg,
1748 FieldAddress(value_reg, TypedData::length_offset()));
1749 __ movl(field_length_operand, value_cid_reg);
1750 __ jmp(&local_exit); // Updated field length typed data array.
1751 // Check for regular array.
1752 __ Bind(&check_array);
1753 __ cmpl(value_cid_reg, Immediate(kImmutableArrayCid));
1754 __ j(GREATER, &local_fail);
1755 __ cmpl(value_cid_reg, Immediate(kArrayCid));
1756 __ j(LESS, &local_fail);
1757 // Destroy value_cid_reg (safe because we are finished with it).
1758 __ movl(value_cid_reg,
1759 FieldAddress(value_reg, Array::length_offset()));
1760 __ movl(field_length_operand, value_cid_reg);
1761 __ jmp(&local_exit); // Updated field length from regular array.
1762
1763 __ Bind(&local_fail);
1764 __ movl(field_length_operand, Immediate(Field::kNoLength));
1765
1766 __ Bind(&local_exit);
1660 } else { 1767 } else {
1768 if (value_cid_reg == kNoRegister) {
1769 ASSERT(!compiler->is_optimizing());
1770 value_cid_reg = EDX;
1771 ASSERT((value_cid_reg != value_reg) && (field_reg != value_cid_reg));
1772 }
1773 ASSERT(value_cid_reg != kNoRegister);
1774 ASSERT(field_reg != kNoRegister);
1661 __ movl(field_cid_operand, Immediate(value_cid)); 1775 __ movl(field_cid_operand, Immediate(value_cid));
1662 __ movl(field_nullability_operand, Immediate(value_cid)); 1776 __ movl(field_nullability_operand, Immediate(value_cid));
1777 if ((value_cid == kArrayCid) || (value_cid == kImmutableArrayCid)) {
1778 // Destroy value_cid_reg (safe because we are finished with it).
1779 __ movl(value_cid_reg,
1780 FieldAddress(value_reg, Array::length_offset()));
1781 __ movl(field_length_operand, value_cid_reg);
1782 } else if (RawObject::IsTypedDataClassId(value_cid)) {
1783 // Destroy value_cid_reg (safe because we are finished with it).
1784 __ movl(value_cid_reg,
1785 FieldAddress(value_reg, TypedData::length_offset()));
1786 __ movl(field_length_operand, value_cid_reg);
1787 } else {
1788 __ movl(field_length_operand, Immediate(Field::kNoLength));
1789 }
1663 } 1790 }
1664 1791
1665 if (!ok_is_fall_through) { 1792 if (!ok_is_fall_through) {
1666 __ jmp(&ok); 1793 __ jmp(&ok);
1667 } 1794 }
1668 } else { 1795 } else {
1796 // Field guard class has been initialized and is known.
1797
1798 if (field_reg != kNoRegister) {
1799 __ LoadObject(field_reg, Field::ZoneHandle(field().raw()));
1800 }
1801
1669 if (value_cid == kDynamicCid) { 1802 if (value_cid == kDynamicCid) {
1670 // Field's guarded class id is fixed by value's class id is not known. 1803 // Value's class id is not known.
1671 __ testl(value_reg, Immediate(kSmiTagMask)); 1804 __ testl(value_reg, Immediate(kSmiTagMask));
1672 1805
1673 if (field_cid != kSmiCid) { 1806 if (field_cid != kSmiCid) {
1807 // value is a smi.
1674 __ j(ZERO, fail); 1808 __ j(ZERO, fail);
1675 __ LoadClassId(value_cid_reg, value_reg); 1809 __ LoadClassId(value_cid_reg, value_reg);
1676 __ cmpl(value_cid_reg, Immediate(field_cid)); 1810 __ cmpl(value_cid_reg, Immediate(field_cid));
1677 } 1811 }
1678 1812
1813 if (field_has_length) {
1814 // Jump when Value CID != Field guard CID
1815 __ j(NOT_EQUAL, fail);
1816
1817 // Classes are same, perform guarded list length check.
1818 ASSERT(field_reg != kNoRegister);
1819 ASSERT(value_cid_reg != kNoRegister);
1820 FieldAddress field_length_operand(
1821 field_reg, Field::guarded_list_length_offset());
1822 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1823 // Destroy value_cid_reg (safe because we are finished with it).
1824 __ movl(value_cid_reg,
1825 FieldAddress(value_reg, Array::length_offset()));
1826 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1827 // Destroy value_cid_reg (safe because we are finished with it).
1828 __ movl(value_cid_reg,
1829 FieldAddress(value_reg, TypedData::length_offset()));
1830 }
1831 __ cmpl(value_cid_reg, field_length_operand);
1832 }
1833
1679 if (field().is_nullable() && (field_cid != kNullCid)) { 1834 if (field().is_nullable() && (field_cid != kNullCid)) {
1680 __ j(EQUAL, &ok); 1835 __ j(EQUAL, &ok);
1681 const Immediate& raw_null = 1836 const Immediate& raw_null =
1682 Immediate(reinterpret_cast<intptr_t>(Object::null())); 1837 Immediate(reinterpret_cast<intptr_t>(Object::null()));
1683 __ cmpl(value_reg, raw_null); 1838 __ cmpl(value_reg, raw_null);
1684 } 1839 }
1685 1840
1686 if (ok_is_fall_through) { 1841 if (ok_is_fall_through) {
1687 __ j(NOT_EQUAL, fail); 1842 __ j(NOT_EQUAL, fail);
1688 } else { 1843 } else {
1689 __ j(EQUAL, &ok); 1844 __ j(EQUAL, &ok);
1690 } 1845 }
1691 } else { 1846 } else {
1692 // Both value's and field's class id is known. 1847 // Both value's and field's class id is known.
1693 if ((value_cid != field_cid) && (value_cid != nullability)) { 1848 if ((value_cid != field_cid) && (value_cid != nullability)) {
1694 if (ok_is_fall_through) { 1849 if (ok_is_fall_through) {
1695 __ jmp(fail); 1850 __ jmp(fail);
1696 } 1851 }
1852 } else if (field_has_length && (value_cid == field_cid)) {
1853 ASSERT(value_cid_reg != kNoRegister);
1854 if ((field_cid == kArrayCid) || (field_cid == kImmutableArrayCid)) {
1855 // Destroy value_cid_reg (safe because we are finished with it).
1856 __ movl(value_cid_reg,
1857 FieldAddress(value_reg, Array::length_offset()));
1858 } else if (RawObject::IsTypedDataClassId(field_cid)) {
1859 // Destroy value_cid_reg (safe because we are finished with it).
1860 __ movl(value_cid_reg,
1861 FieldAddress(value_reg, TypedData::length_offset()));
1862 }
1863 __ cmpl(value_cid_reg, Immediate(field_length));
1864 if (ok_is_fall_through) {
1865 __ j(NOT_EQUAL, fail);
1866 }
1697 } else { 1867 } else {
1698 // Nothing to emit. 1868 // Nothing to emit.
1699 ASSERT(!compiler->is_optimizing()); 1869 ASSERT(!compiler->is_optimizing());
1700 return; 1870 return;
1701 } 1871 }
1702 } 1872 }
1703 } 1873 }
1704 1874
1705 if (deopt == NULL) { 1875 if (deopt == NULL) {
1706 ASSERT(!compiler->is_optimizing()); 1876 ASSERT(!compiler->is_optimizing());
(...skipping 3253 matching lines...) Expand 10 before | Expand all | Expand 10 after
4960 PcDescriptors::kOther, 5130 PcDescriptors::kOther,
4961 locs()); 5131 locs());
4962 __ Drop(2); // Discard type arguments and receiver. 5132 __ Drop(2); // Discard type arguments and receiver.
4963 } 5133 }
4964 5134
4965 } // namespace dart 5135 } // namespace dart
4966 5136
4967 #undef __ 5137 #undef __
4968 5138
4969 #endif // defined TARGET_ARCH_IA32 5139 #endif // defined TARGET_ARCH_IA32
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698