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/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 "lib/error.h" | 10 #include "lib/error.h" |
| 11 #include "vm/dart_entry.h" | 11 #include "vm/dart_entry.h" |
| 12 #include "vm/flow_graph_compiler.h" | 12 #include "vm/flow_graph_compiler.h" |
| 13 #include "vm/locations.h" | 13 #include "vm/locations.h" |
| 14 #include "vm/object_store.h" | 14 #include "vm/object_store.h" |
| 15 #include "vm/parser.h" | 15 #include "vm/parser.h" |
| 16 #include "vm/stack_frame.h" | |
| 16 #include "vm/stub_code.h" | 17 #include "vm/stub_code.h" |
| 17 #include "vm/symbols.h" | 18 #include "vm/symbols.h" |
| 18 | 19 |
| 19 #define __ compiler->assembler()-> | 20 #define __ compiler->assembler()-> |
| 20 | 21 |
| 21 namespace dart { | 22 namespace dart { |
| 22 | 23 |
| 23 DECLARE_FLAG(int, optimization_counter_threshold); | 24 DECLARE_FLAG(int, optimization_counter_threshold); |
| 24 DECLARE_FLAG(bool, propagate_ic_data); | 25 DECLARE_FLAG(bool, propagate_ic_data); |
| 25 | 26 |
| (...skipping 1475 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1501 break; | 1502 break; |
| 1502 case kFloat64ArrayCid: | 1503 case kFloat64ArrayCid: |
| 1503 __ movsd(element_address, locs()->in(2).fpu_reg()); | 1504 __ movsd(element_address, locs()->in(2).fpu_reg()); |
| 1504 break; | 1505 break; |
| 1505 default: | 1506 default: |
| 1506 UNREACHABLE(); | 1507 UNREACHABLE(); |
| 1507 } | 1508 } |
| 1508 } | 1509 } |
| 1509 | 1510 |
| 1510 | 1511 |
| 1512 LocationSummary* GuardFieldInstr::MakeLocationSummary() const { | |
| 1513 const intptr_t kNumInputs = 1; | |
| 1514 LocationSummary* summary = | |
| 1515 new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall); | |
| 1516 summary->set_in(0, Location::RequiresRegister()); | |
| 1517 if (value()->Type()->ToCid() == kDynamicCid) { | |
| 1518 summary->AddTemp(Location::RequiresRegister()); | |
| 1519 } | |
| 1520 if (field().guarded_cid() == kIllegalCid) { | |
| 1521 summary->AddTemp(Location::RequiresRegister()); | |
| 1522 } | |
| 1523 return summary; | |
| 1524 } | |
| 1525 | |
| 1526 | |
| 1527 static void PushCid(FlowGraphCompiler* compiler, const Immediate& imm) { | |
| 1528 __ pushl(Immediate(Smi::RawValue(imm.value()))); | |
| 1529 } | |
| 1530 | |
| 1531 | |
| 1532 static void PushCid(FlowGraphCompiler* compiler, Register reg) { | |
| 1533 __ SmiTag(reg); | |
| 1534 __ pushl(reg); | |
| 1535 } | |
| 1536 | |
| 1537 | |
| 1538 template<typename ValueCidOperandType> | |
| 1539 static void EmitCidGuardInit(FlowGraphCompiler* compiler, | |
| 1540 ValueCidOperandType value_cid, | |
| 1541 const Immediate& field_cid, | |
| 1542 const Immediate& nullability, | |
| 1543 Label* deopt, | |
| 1544 Label* ok) { | |
| 1545 // nothing to do. | |
| 1546 } | |
| 1547 | |
| 1548 | |
| 1549 template<typename ValueCidOperandType> | |
| 1550 static void EmitCidGuardInit(FlowGraphCompiler* compiler, | |
| 1551 ValueCidOperandType value_cid, | |
| 1552 const FieldAddress& field_cid, | |
| 1553 const FieldAddress& nullability, | |
| 1554 Label* deopt, | |
| 1555 Label* ok) { | |
| 1556 // Check if field is initialized for the first time. | |
| 1557 Label fail; | |
| 1558 __ cmpl(field_cid, Immediate(kIllegalCid)); | |
| 1559 __ j(NOT_EQUAL, (deopt != NULL) ? deopt : &fail); | |
| 1560 __ movl(field_cid, value_cid); | |
| 1561 __ movl(nullability, value_cid); | |
| 1562 __ jmp(ok); | |
| 1563 if (deopt == NULL) { | |
| 1564 __ Bind(&fail); | |
| 1565 } | |
| 1566 } | |
| 1567 | |
| 1568 | |
| 1569 static void CompareJump(FlowGraphCompiler* compiler, | |
| 1570 Condition cond, | |
| 1571 const Immediate& left, | |
| 1572 const Immediate& right, | |
| 1573 Label* target) { | |
| 1574 if ((left.value() == right.value()) && (cond == EQUAL)) { | |
| 1575 __ jmp(target); | |
| 1576 } else if ((left.value() != right.value()) && cond == NOT_EQUAL) { | |
| 1577 __ jmp(target); | |
| 1578 } | |
| 1579 } | |
| 1580 | |
| 1581 | |
| 1582 static void CompareJump(FlowGraphCompiler* compiler, | |
| 1583 Condition cond, | |
| 1584 Immediate left, | |
| 1585 Register right, | |
| 1586 Label* target) { | |
| 1587 ASSERT((cond == EQUAL) || (cond == NOT_EQUAL)); | |
| 1588 __ cmpl(right, left); | |
| 1589 __ j(cond, target); | |
| 1590 } | |
| 1591 | |
| 1592 | |
| 1593 template<typename LeftT, typename RightT> | |
|
Kevin Millikin (Google)
2013/03/12 12:14:56
Spell out Type like below, or at least be uniform.
Vyacheslav Egorov (Google)
2013/03/12 16:54:40
Done.
| |
| 1594 static void CompareJump(FlowGraphCompiler* compiler, | |
| 1595 Condition cond, | |
| 1596 LeftT left, | |
| 1597 RightT right, | |
| 1598 Label* target) { | |
| 1599 __ cmpl(left, right); | |
| 1600 __ j(cond, target); | |
| 1601 } | |
| 1602 | |
| 1603 | |
| 1604 template<typename ValueCidOperandType, | |
| 1605 typename FieldCidOperandType, | |
| 1606 typename FieldNullabilityOperandType> | |
| 1607 static void EmitCidGuard(FlowGraphCompiler* compiler, | |
| 1608 const Field& field, | |
|
Kevin Millikin (Google)
2013/03/12 12:14:56
The templates are kind of messy because you have t
Vyacheslav Egorov (Google)
2013/03/12 16:54:40
Done.
| |
| 1609 ValueCidOperandType value_cid, | |
| 1610 FieldCidOperandType field_cid, | |
| 1611 FieldNullabilityOperandType nullability, | |
| 1612 Label* deopt) { | |
| 1613 Label ok, update; | |
| 1614 CompareJump(compiler, EQUAL, field_cid, value_cid, &ok); | |
| 1615 if ((deopt != NULL) && (field.guarded_cid() != kIllegalCid)) { | |
| 1616 CompareJump(compiler, NOT_EQUAL, nullability, value_cid, deopt); | |
| 1617 } else { | |
| 1618 CompareJump(compiler, EQUAL, nullability, value_cid, &ok); | |
| 1619 } | |
| 1620 | |
| 1621 EmitCidGuardInit(compiler, value_cid, field_cid, nullability, deopt, &ok); | |
| 1622 | |
| 1623 if (deopt == NULL) { | |
| 1624 // Switch field's cid to dynamic and notify runtime. | |
| 1625 CompareJump(compiler, EQUAL, field_cid, Immediate(kDynamicCid), &ok); | |
| 1626 __ PushObject(field); | |
| 1627 PushCid(compiler, value_cid); | |
| 1628 __ CallRuntime(kUpdateFieldCidRuntimeEntry); | |
| 1629 __ Drop(2); | |
| 1630 } | |
| 1631 | |
| 1632 __ Bind(&ok); | |
| 1633 } | |
| 1634 | |
| 1635 | |
| 1636 template<typename FieldCidOperandType, typename FieldNullabilityOperandType> | |
| 1637 static void EmitCidGuard(FlowGraphCompiler* compiler, | |
| 1638 const Field& field, | |
| 1639 intptr_t value_cid, | |
| 1640 Register value_cid_reg, | |
| 1641 FieldCidOperandType field_cid, | |
| 1642 FieldNullabilityOperandType nullability, | |
| 1643 Label* deopt) { | |
| 1644 if (value_cid == kDynamicCid) { | |
| 1645 EmitCidGuard(compiler, field, value_cid_reg, field_cid, nullability, deopt); | |
| 1646 } else { | |
| 1647 EmitCidGuard(compiler, | |
| 1648 field, | |
| 1649 Immediate(value_cid), | |
| 1650 field_cid, | |
| 1651 nullability, | |
| 1652 deopt); | |
| 1653 } | |
| 1654 } | |
| 1655 | |
| 1656 | |
| 1657 static void EmitFieldGuard(FlowGraphCompiler* compiler, | |
| 1658 Register value_reg, | |
| 1659 const Field& field, | |
| 1660 intptr_t value_cid, | |
| 1661 Register value_cid_reg, | |
| 1662 intptr_t field_cid, | |
| 1663 intptr_t nullability, | |
| 1664 Register field_reg, | |
| 1665 Label* deopt) { | |
| 1666 if (value_cid == kDynamicCid) { | |
| 1667 Label not_smi, cid_loaded; | |
| 1668 __ testl(value_reg, Immediate(kSmiTagMask)); | |
| 1669 __ j(NOT_ZERO, ¬_smi, Assembler::kNearJump); | |
| 1670 __ movl(value_cid_reg, Immediate(kSmiCid)); | |
| 1671 __ jmp(&cid_loaded); | |
| 1672 __ Bind(¬_smi); | |
| 1673 __ LoadClassId(value_cid_reg, value_reg); | |
| 1674 __ Bind(&cid_loaded); | |
| 1675 } | |
| 1676 | |
| 1677 if (field_cid == kIllegalCid) { | |
| 1678 __ LoadObject(field_reg, Field::ZoneHandle(field.raw())); | |
| 1679 EmitCidGuard(compiler, | |
| 1680 field, | |
| 1681 value_cid, | |
| 1682 value_cid_reg, | |
| 1683 FieldAddress(field_reg, Field::guarded_cid_offset()), | |
| 1684 FieldAddress(field_reg, Field::is_nullable_offset()), | |
| 1685 deopt); | |
| 1686 } else { | |
| 1687 EmitCidGuard(compiler, | |
| 1688 field, | |
| 1689 value_cid, | |
| 1690 value_cid_reg, | |
| 1691 Immediate(field_cid), | |
| 1692 Immediate(nullability), | |
| 1693 deopt); | |
| 1694 } | |
| 1695 } | |
| 1696 | |
| 1697 | |
| 1698 void GuardFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | |
| 1699 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1700 const intptr_t field_cid = field().guarded_cid(); | |
| 1701 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | |
| 1702 | |
| 1703 Register value_reg = locs()->in(0).reg(); | |
| 1704 | |
| 1705 Register value_cid_reg = (value_cid == kDynamicCid) ? | |
| 1706 locs()->temp(0).reg() : kNoRegister; | |
| 1707 | |
| 1708 Label* deopt = compiler->is_optimizing() && CanDeoptimize() ? | |
| 1709 compiler->AddDeoptStub(deopt_id(), kDeoptStoreInstanceField) : NULL; | |
| 1710 | |
| 1711 if ((deopt != NULL) && (field_cid != kIllegalCid)) { | |
| 1712 if (value_cid != kDynamicCid) { | |
| 1713 ASSERT(field_cid != value_cid); | |
| 1714 __ jmp(deopt); | |
| 1715 return; | |
| 1716 } | |
| 1717 | |
| 1718 if (field_cid == kSmiCid) { | |
| 1719 __ testl(value_reg, Immediate(kSmiTagMask)); | |
| 1720 } else { | |
| 1721 ASSERT(value_cid_reg != kNoRegister); | |
| 1722 __ testl(value_reg, Immediate(kSmiTagMask)); | |
| 1723 __ j(ZERO, deopt); | |
| 1724 __ LoadClassId(value_cid_reg, value_reg); | |
| 1725 __ cmpl(value_cid_reg, Immediate(field_cid)); | |
| 1726 } | |
| 1727 | |
| 1728 if (field().is_nullable()) { | |
| 1729 Label ok; | |
| 1730 __ j(EQUAL, &ok); | |
| 1731 const Immediate& raw_null = | |
| 1732 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 1733 __ cmpl(value_reg, raw_null); | |
| 1734 __ j(NOT_EQUAL, deopt); | |
| 1735 __ Bind(&ok); | |
| 1736 } else { | |
| 1737 __ j(NOT_EQUAL, deopt); | |
| 1738 } | |
| 1739 | |
| 1740 return; | |
| 1741 } | |
| 1742 | |
| 1743 Register field_reg = (field_cid == kIllegalCid) ? | |
| 1744 locs()->temp(1).reg() : kNoRegister; | |
| 1745 | |
| 1746 EmitFieldGuard(compiler, | |
| 1747 value_reg, | |
| 1748 field(), | |
| 1749 value_cid, value_cid_reg, | |
| 1750 field_cid, nullability, field_reg, | |
| 1751 deopt); | |
| 1752 } | |
| 1753 | |
| 1754 | |
| 1511 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { | 1755 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { |
| 1512 const intptr_t kNumInputs = 2; | 1756 const intptr_t kNumInputs = 2; |
| 1513 const intptr_t num_temps = 0; | 1757 const intptr_t num_temps = 0; |
| 1514 LocationSummary* summary = | 1758 LocationSummary* summary = |
| 1515 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); | 1759 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); |
| 1516 summary->set_in(0, Location::RequiresRegister()); | 1760 summary->set_in(0, Location::RequiresRegister()); |
| 1517 summary->set_in(1, ShouldEmitStoreBarrier() | 1761 if (ShouldEmitStoreBarrier() || should_emit_field_guard()) { |
| 1518 ? Location::WritableRegister() | 1762 summary->set_in(1, Location::WritableRegister()); |
| 1519 : Location::RegisterOrConstant(value())); | 1763 } else { |
| 1764 summary->set_in(1, Location::RegisterOrConstant(value())); | |
| 1765 } | |
| 1766 | |
| 1767 if (should_emit_field_guard()) { | |
| 1768 summary->AddTemp(Location::RequiresRegister()); | |
| 1769 summary->AddTemp(Location::RequiresRegister()); | |
| 1770 } | |
| 1771 | |
| 1520 return summary; | 1772 return summary; |
| 1521 } | 1773 } |
| 1522 | 1774 |
| 1523 | 1775 |
| 1524 void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 1776 void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 1525 Register instance_reg = locs()->in(0).reg(); | 1777 Register instance_reg = locs()->in(0).reg(); |
| 1778 | |
| 1779 if (should_emit_field_guard()) { | |
| 1780 ASSERT(!compiler->is_optimizing()); | |
| 1781 Register value_reg = locs()->in(1).reg(); | |
| 1782 Register value_cid_reg = locs()->temp(0).reg(); | |
| 1783 Register field_reg = locs()->temp(1).reg(); | |
| 1784 | |
| 1785 __ pushl(instance_reg); | |
| 1786 __ pushl(value_reg); | |
| 1787 EmitFieldGuard(compiler, | |
| 1788 value_reg, | |
| 1789 field(), | |
| 1790 kDynamicCid, | |
| 1791 value_cid_reg, | |
| 1792 kIllegalCid, | |
| 1793 kIllegalCid, | |
| 1794 field_reg, | |
| 1795 NULL); | |
| 1796 __ popl(value_reg); | |
| 1797 __ popl(instance_reg); | |
| 1798 } | |
| 1799 | |
| 1526 if (ShouldEmitStoreBarrier()) { | 1800 if (ShouldEmitStoreBarrier()) { |
| 1527 Register value_reg = locs()->in(1).reg(); | 1801 Register value_reg = locs()->in(1).reg(); |
| 1528 __ StoreIntoObject(instance_reg, | 1802 __ StoreIntoObject(instance_reg, |
| 1529 FieldAddress(instance_reg, field().Offset()), value_reg); | 1803 FieldAddress(instance_reg, field().Offset()), value_reg); |
| 1530 } else { | 1804 } else { |
| 1531 if (locs()->in(1).IsConstant()) { | 1805 if (locs()->in(1).IsConstant()) { |
| 1532 __ StoreIntoObjectNoBarrier( | 1806 __ StoreIntoObjectNoBarrier( |
| 1533 instance_reg, | 1807 instance_reg, |
| 1534 FieldAddress(instance_reg, field().Offset()), | 1808 FieldAddress(instance_reg, field().Offset()), |
| 1535 locs()->in(1).constant()); | 1809 locs()->in(1).constant()); |
| (...skipping 1285 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2821 } | 3095 } |
| 2822 | 3096 |
| 2823 | 3097 |
| 2824 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3098 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2825 comparison()->EmitBranchCode(compiler, this); | 3099 comparison()->EmitBranchCode(compiler, this); |
| 2826 } | 3100 } |
| 2827 | 3101 |
| 2828 | 3102 |
| 2829 LocationSummary* CheckClassInstr::MakeLocationSummary() const { | 3103 LocationSummary* CheckClassInstr::MakeLocationSummary() const { |
| 2830 const intptr_t kNumInputs = 1; | 3104 const intptr_t kNumInputs = 1; |
| 2831 const intptr_t kNumTemps = 1; | 3105 const intptr_t kNumTemps = 0; |
| 2832 LocationSummary* summary = | 3106 LocationSummary* summary = |
| 2833 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3107 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2834 summary->set_in(0, Location::RequiresRegister()); | 3108 summary->set_in(0, Location::RequiresRegister()); |
| 2835 summary->set_temp(0, Location::RequiresRegister()); | 3109 if (!null_check()) { |
| 3110 summary->AddTemp(Location::RequiresRegister()); | |
| 3111 } | |
| 2836 return summary; | 3112 return summary; |
| 2837 } | 3113 } |
| 2838 | 3114 |
| 2839 | 3115 |
| 2840 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3116 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3117 if (null_check()) { | |
| 3118 Label* deopt = compiler->AddDeoptStub(deopt_id(), | |
| 3119 kDeoptCheckClass); | |
| 3120 const Immediate& raw_null = | |
| 3121 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 3122 __ cmpl(locs()->in(0).reg(), raw_null); | |
| 3123 __ j(EQUAL, deopt); | |
| 3124 return; | |
| 3125 } | |
| 3126 | |
| 2841 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || | 3127 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || |
| 2842 (unary_checks().NumberOfChecks() > 1)); | 3128 (unary_checks().NumberOfChecks() > 1)); |
| 2843 Register value = locs()->in(0).reg(); | 3129 Register value = locs()->in(0).reg(); |
| 2844 Register temp = locs()->temp(0).reg(); | 3130 Register temp = locs()->temp(0).reg(); |
| 2845 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 3131 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2846 kDeoptCheckClass); | 3132 kDeoptCheckClass); |
| 2847 Label is_ok; | 3133 Label is_ok; |
| 2848 intptr_t cix = 0; | 3134 intptr_t cix = 0; |
| 2849 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { | 3135 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { |
| 2850 __ testl(value, Immediate(kSmiTagMask)); | 3136 __ testl(value, Immediate(kSmiTagMask)); |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3554 PcDescriptors::kOther, | 3840 PcDescriptors::kOther, |
| 3555 locs()); | 3841 locs()); |
| 3556 __ Drop(2); // Discard type arguments and receiver. | 3842 __ Drop(2); // Discard type arguments and receiver. |
| 3557 } | 3843 } |
| 3558 | 3844 |
| 3559 } // namespace dart | 3845 } // namespace dart |
| 3560 | 3846 |
| 3561 #undef __ | 3847 #undef __ |
| 3562 | 3848 |
| 3563 #endif // defined TARGET_ARCH_IA32 | 3849 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |