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> | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
I'm still not liking the templates. As the writer
| |
| 1539 static void EmitCidGuardInit(FlowGraphCompiler* compiler, | |
| 1540 ValueCidOperandType value_cid, | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
Indentation is screwy.
| |
| 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, | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
According to the suggestion above, you could inlin
| |
| 1551 ValueCidOperandType value_cid, | |
| 1552 const FieldAddress& field_cid, | |
| 1553 const FieldAddress& nullability, | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
Indentation is screwy.
| |
| 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); | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
In the case that deopt != NULL, then this will emi
| |
| 1563 if (deopt == NULL) { | |
| 1564 __ Bind(&fail); | |
| 1565 } | |
| 1566 } | |
| 1567 | |
| 1568 | |
| 1569 static void CompareJump(FlowGraphCompiler* compiler, | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
I don't think this one is necessary.
| |
| 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 LeftOperandType, typename RightOperandType> | |
| 1594 static void CompareJump(FlowGraphCompiler* compiler, | |
| 1595 Condition cond, | |
| 1596 LeftOperandType left, | |
| 1597 RightOperandType 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, | |
| 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); | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
I think this case is impossible. The caller has a
| |
| 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 field_cid = field().guarded_cid(); | |
| 1700 | |
| 1701 if (field_cid == kDynamicCid) { | |
| 1702 ASSERT(!compiler->is_optimizing()); | |
| 1703 return; // Nothing to emit. | |
| 1704 } | |
| 1705 | |
| 1706 const intptr_t value_cid = value()->Type()->ToCid(); | |
| 1707 const intptr_t nullability = field().is_nullable() ? kNullCid : kIllegalCid; | |
| 1708 | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
There is an extra blank line here.
| |
| 1709 | |
| 1710 Register value_reg = locs()->in(0).reg(); | |
| 1711 | |
| 1712 Register value_cid_reg = (value_cid == kDynamicCid) ? | |
| 1713 locs()->temp(0).reg() : kNoRegister; | |
| 1714 | |
| 1715 Label* deopt = compiler->is_optimizing() && CanDeoptimize() ? | |
|
Kevin Millikin (Google)
2013/03/13 16:03:36
CanDeoptimize() returns the constant true, or am I
| |
| 1716 compiler->AddDeoptStub(deopt_id(), kDeoptStoreInstanceField) : NULL; | |
| 1717 | |
| 1718 if ((deopt != NULL) && (field_cid != kIllegalCid)) { | |
| 1719 if (value_cid != kDynamicCid) { | |
| 1720 ASSERT(field_cid != value_cid); | |
| 1721 __ jmp(deopt); | |
| 1722 return; | |
| 1723 } | |
| 1724 | |
| 1725 if (field_cid == kSmiCid) { | |
| 1726 __ testl(value_reg, Immediate(kSmiTagMask)); | |
| 1727 } else { | |
| 1728 ASSERT(value_cid_reg != kNoRegister); | |
| 1729 __ testl(value_reg, Immediate(kSmiTagMask)); | |
| 1730 __ j(ZERO, deopt); | |
| 1731 __ LoadClassId(value_cid_reg, value_reg); | |
| 1732 __ cmpl(value_cid_reg, Immediate(field_cid)); | |
| 1733 } | |
| 1734 | |
| 1735 if (field().is_nullable()) { | |
| 1736 Label ok; | |
| 1737 __ j(EQUAL, &ok); | |
| 1738 const Immediate& raw_null = | |
| 1739 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 1740 __ cmpl(value_reg, raw_null); | |
| 1741 __ j(NOT_EQUAL, deopt); | |
| 1742 __ Bind(&ok); | |
| 1743 } else { | |
| 1744 __ j(NOT_EQUAL, deopt); | |
| 1745 } | |
| 1746 | |
| 1747 return; | |
| 1748 } | |
| 1749 | |
| 1750 Register field_reg = (field_cid == kIllegalCid) ? | |
| 1751 locs()->temp(value_cid_reg == kNoRegister ? 0 : 1).reg() : kNoRegister; | |
| 1752 | |
| 1753 EmitFieldGuard(compiler, | |
| 1754 value_reg, | |
| 1755 field(), | |
| 1756 value_cid, value_cid_reg, | |
| 1757 field_cid, nullability, field_reg, | |
| 1758 deopt); | |
| 1759 } | |
| 1760 | |
| 1761 | |
| 1511 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { | 1762 LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const { |
| 1512 const intptr_t kNumInputs = 2; | 1763 const intptr_t kNumInputs = 2; |
| 1513 const intptr_t num_temps = 0; | 1764 const intptr_t num_temps = 0; |
| 1514 LocationSummary* summary = | 1765 LocationSummary* summary = |
| 1515 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); | 1766 new LocationSummary(kNumInputs, num_temps, LocationSummary::kNoCall); |
| 1516 summary->set_in(0, Location::RequiresRegister()); | 1767 summary->set_in(0, Location::RequiresRegister()); |
| 1517 summary->set_in(1, ShouldEmitStoreBarrier() | 1768 summary->set_in(1, ShouldEmitStoreBarrier() |
| 1518 ? Location::WritableRegister() | 1769 ? Location::WritableRegister() |
| 1519 : Location::RegisterOrConstant(value())); | 1770 : Location::RegisterOrConstant(value())); |
| 1520 return summary; | 1771 return summary; |
| (...skipping 1300 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2821 } | 3072 } |
| 2822 | 3073 |
| 2823 | 3074 |
| 2824 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3075 void BranchInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 2825 comparison()->EmitBranchCode(compiler, this); | 3076 comparison()->EmitBranchCode(compiler, this); |
| 2826 } | 3077 } |
| 2827 | 3078 |
| 2828 | 3079 |
| 2829 LocationSummary* CheckClassInstr::MakeLocationSummary() const { | 3080 LocationSummary* CheckClassInstr::MakeLocationSummary() const { |
| 2830 const intptr_t kNumInputs = 1; | 3081 const intptr_t kNumInputs = 1; |
| 2831 const intptr_t kNumTemps = 1; | 3082 const intptr_t kNumTemps = 0; |
| 2832 LocationSummary* summary = | 3083 LocationSummary* summary = |
| 2833 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); | 3084 new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall); |
| 2834 summary->set_in(0, Location::RequiresRegister()); | 3085 summary->set_in(0, Location::RequiresRegister()); |
| 2835 summary->set_temp(0, Location::RequiresRegister()); | 3086 if (!null_check()) { |
| 3087 summary->AddTemp(Location::RequiresRegister()); | |
| 3088 } | |
| 2836 return summary; | 3089 return summary; |
| 2837 } | 3090 } |
| 2838 | 3091 |
| 2839 | 3092 |
| 2840 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { | 3093 void CheckClassInstr::EmitNativeCode(FlowGraphCompiler* compiler) { |
| 3094 if (null_check()) { | |
| 3095 Label* deopt = compiler->AddDeoptStub(deopt_id(), | |
| 3096 kDeoptCheckClass); | |
| 3097 const Immediate& raw_null = | |
| 3098 Immediate(reinterpret_cast<intptr_t>(Object::null())); | |
| 3099 __ cmpl(locs()->in(0).reg(), raw_null); | |
| 3100 __ j(EQUAL, deopt); | |
| 3101 return; | |
| 3102 } | |
| 3103 | |
| 2841 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || | 3104 ASSERT((unary_checks().GetReceiverClassIdAt(0) != kSmiCid) || |
| 2842 (unary_checks().NumberOfChecks() > 1)); | 3105 (unary_checks().NumberOfChecks() > 1)); |
| 2843 Register value = locs()->in(0).reg(); | 3106 Register value = locs()->in(0).reg(); |
| 2844 Register temp = locs()->temp(0).reg(); | 3107 Register temp = locs()->temp(0).reg(); |
| 2845 Label* deopt = compiler->AddDeoptStub(deopt_id(), | 3108 Label* deopt = compiler->AddDeoptStub(deopt_id(), |
| 2846 kDeoptCheckClass); | 3109 kDeoptCheckClass); |
| 2847 Label is_ok; | 3110 Label is_ok; |
| 2848 intptr_t cix = 0; | 3111 intptr_t cix = 0; |
| 2849 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { | 3112 if (unary_checks().GetReceiverClassIdAt(cix) == kSmiCid) { |
| 2850 __ testl(value, Immediate(kSmiTagMask)); | 3113 __ testl(value, Immediate(kSmiTagMask)); |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3554 PcDescriptors::kOther, | 3817 PcDescriptors::kOther, |
| 3555 locs()); | 3818 locs()); |
| 3556 __ Drop(2); // Discard type arguments and receiver. | 3819 __ Drop(2); // Discard type arguments and receiver. |
| 3557 } | 3820 } |
| 3558 | 3821 |
| 3559 } // namespace dart | 3822 } // namespace dart |
| 3560 | 3823 |
| 3561 #undef __ | 3824 #undef __ |
| 3562 | 3825 |
| 3563 #endif // defined TARGET_ARCH_IA32 | 3826 #endif // defined TARGET_ARCH_IA32 |
| OLD | NEW |