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" // NOLINT | 5 #include "vm/globals.h" // NOLINT |
6 #if defined(TARGET_ARCH_ARM) | 6 #if defined(TARGET_ARCH_ARM) |
7 | 7 |
8 #include "vm/assembler.h" | 8 #include "vm/assembler.h" |
9 #include "vm/cpu.h" | 9 #include "vm/cpu.h" |
10 #include "vm/longjump.h" | 10 #include "vm/longjump.h" |
(...skipping 1516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1527 | 1527 |
1528 | 1528 |
1529 intptr_t Assembler::FindImmediate(int32_t imm) { | 1529 intptr_t Assembler::FindImmediate(int32_t imm) { |
1530 return object_pool_wrapper_.FindImmediate(imm); | 1530 return object_pool_wrapper_.FindImmediate(imm); |
1531 } | 1531 } |
1532 | 1532 |
1533 | 1533 |
1534 // Uses a code sequence that can easily be decoded. | 1534 // Uses a code sequence that can easily be decoded. |
1535 void Assembler::LoadWordFromPoolOffset(Register rd, | 1535 void Assembler::LoadWordFromPoolOffset(Register rd, |
1536 int32_t offset, | 1536 int32_t offset, |
| 1537 Register pp, |
1537 Condition cond) { | 1538 Condition cond) { |
1538 ASSERT(constant_pool_allowed()); | 1539 ASSERT((pp != PP) || constant_pool_allowed()); |
1539 ASSERT(rd != PP); | 1540 ASSERT(rd != pp); |
1540 int32_t offset_mask = 0; | 1541 int32_t offset_mask = 0; |
1541 if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) { | 1542 if (Address::CanHoldLoadOffset(kWord, offset, &offset_mask)) { |
1542 ldr(rd, Address(PP, offset), cond); | 1543 ldr(rd, Address(pp, offset), cond); |
1543 } else { | 1544 } else { |
1544 int32_t offset_hi = offset & ~offset_mask; // signed | 1545 int32_t offset_hi = offset & ~offset_mask; // signed |
1545 uint32_t offset_lo = offset & offset_mask; // unsigned | 1546 uint32_t offset_lo = offset & offset_mask; // unsigned |
1546 // Inline a simplified version of AddImmediate(rd, PP, offset_hi). | 1547 // Inline a simplified version of AddImmediate(rd, pp, offset_hi). |
1547 Operand o; | 1548 Operand o; |
1548 if (Operand::CanHold(offset_hi, &o)) { | 1549 if (Operand::CanHold(offset_hi, &o)) { |
1549 add(rd, PP, o, cond); | 1550 add(rd, pp, o, cond); |
1550 } else { | 1551 } else { |
1551 LoadImmediate(rd, offset_hi, cond); | 1552 LoadImmediate(rd, offset_hi, cond); |
1552 add(rd, PP, Operand(rd), cond); | 1553 add(rd, pp, Operand(rd), cond); |
1553 } | 1554 } |
1554 ldr(rd, Address(rd, offset_lo), cond); | 1555 ldr(rd, Address(rd, offset_lo), cond); |
1555 } | 1556 } |
1556 } | 1557 } |
1557 | 1558 |
| 1559 void Assembler::CheckCodePointer() { |
| 1560 #ifdef DEBUG |
| 1561 Label cid_ok, instructions_ok; |
| 1562 Push(R0); |
| 1563 Push(IP); |
| 1564 CompareClassId(CODE_REG, kCodeCid, R0); |
| 1565 b(&cid_ok, EQ); |
| 1566 bkpt(0); |
| 1567 Bind(&cid_ok); |
1558 | 1568 |
1559 void Assembler::LoadPoolPointer() { | 1569 const intptr_t offset = CodeSize() + Instr::kPCReadOffset + |
1560 const intptr_t object_pool_pc_dist = | 1570 Instructions::HeaderSize() - kHeapObjectTag; |
1561 Instructions::HeaderSize() - Instructions::object_pool_offset() + | 1571 mov(R0, Operand(PC)); |
1562 CodeSize() + Instr::kPCReadOffset; | 1572 AddImmediate(R0, R0, -offset); |
1563 LoadFromOffset(kWord, PP, PC, -object_pool_pc_dist); | 1573 ldr(IP, FieldAddress(CODE_REG, Code::saved_instructions_offset())); |
1564 set_constant_pool_allowed(true); | 1574 cmp(R0, Operand(IP)); |
| 1575 b(&instructions_ok, EQ); |
| 1576 bkpt(1); |
| 1577 Bind(&instructions_ok); |
| 1578 Pop(IP); |
| 1579 Pop(R0); |
| 1580 #endif |
1565 } | 1581 } |
1566 | 1582 |
1567 | 1583 |
| 1584 void Assembler::RestoreCodePointer() { |
| 1585 ldr(CODE_REG, Address(FP, kPcMarkerSlotFromFp * kWordSize)); |
| 1586 CheckCodePointer(); |
| 1587 } |
| 1588 |
| 1589 |
| 1590 void Assembler::LoadPoolPointer(Register reg) { |
| 1591 // Load new pool pointer. |
| 1592 CheckCodePointer(); |
| 1593 ldr(reg, FieldAddress(CODE_REG, Code::object_pool_offset())); |
| 1594 set_constant_pool_allowed(reg == PP); |
| 1595 } |
| 1596 |
| 1597 |
1568 void Assembler::LoadIsolate(Register rd) { | 1598 void Assembler::LoadIsolate(Register rd) { |
1569 ldr(rd, Address(THR, Thread::isolate_offset())); | 1599 ldr(rd, Address(THR, Thread::isolate_offset())); |
1570 } | 1600 } |
1571 | 1601 |
1572 | 1602 |
1573 bool Assembler::CanLoadFromObjectPool(const Object& object) const { | 1603 bool Assembler::CanLoadFromObjectPool(const Object& object) const { |
1574 ASSERT(!Thread::CanLoadFromThread(object)); | 1604 ASSERT(!Thread::CanLoadFromThread(object)); |
1575 if (!constant_pool_allowed()) { | 1605 if (!constant_pool_allowed()) { |
1576 return false; | 1606 return false; |
1577 } | 1607 } |
1578 | 1608 |
1579 ASSERT(object.IsNotTemporaryScopedHandle()); | 1609 ASSERT(object.IsNotTemporaryScopedHandle()); |
1580 ASSERT(object.IsOld()); | 1610 ASSERT(object.IsOld()); |
1581 return true; | 1611 return true; |
1582 } | 1612 } |
1583 | 1613 |
1584 | 1614 |
1585 void Assembler::LoadObjectHelper(Register rd, | 1615 void Assembler::LoadObjectHelper(Register rd, |
1586 const Object& object, | 1616 const Object& object, |
1587 Condition cond, | 1617 Condition cond, |
1588 bool is_unique) { | 1618 bool is_unique, |
| 1619 Register pp) { |
| 1620 // Load common VM constants from the thread. This works also in places where |
| 1621 // no constant pool is set up (e.g. intrinsic code). |
1589 if (Thread::CanLoadFromThread(object)) { | 1622 if (Thread::CanLoadFromThread(object)) { |
1590 // Load common VM constants from the thread. This works also in places where | 1623 // Load common VM constants from the thread. This works also in places where |
1591 // no constant pool is set up (e.g. intrinsic code). | 1624 // no constant pool is set up (e.g. intrinsic code). |
1592 ldr(rd, Address(THR, Thread::OffsetFromThread(object)), cond); | 1625 ldr(rd, Address(THR, Thread::OffsetFromThread(object)), cond); |
1593 } else if (object.IsSmi()) { | 1626 } else if (object.IsSmi()) { |
1594 // Relocation doesn't apply to Smis. | 1627 // Relocation doesn't apply to Smis. |
1595 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond); | 1628 LoadImmediate(rd, reinterpret_cast<int32_t>(object.raw()), cond); |
1596 } else if (CanLoadFromObjectPool(object)) { | 1629 } else if (CanLoadFromObjectPool(object)) { |
1597 // Make sure that class CallPattern is able to decode this load from the | 1630 // Make sure that class CallPattern is able to decode this load from the |
1598 // object pool. | 1631 // object pool. |
1599 const int32_t offset = ObjectPool::element_offset( | 1632 const int32_t offset = ObjectPool::element_offset( |
1600 is_unique ? object_pool_wrapper_.AddObject(object) | 1633 is_unique ? object_pool_wrapper_.AddObject(object) |
1601 : object_pool_wrapper_.FindObject(object)); | 1634 : object_pool_wrapper_.FindObject(object)); |
1602 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); | 1635 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, pp, cond); |
1603 } else { | 1636 } else { |
1604 ASSERT(FLAG_allow_absolute_addresses); | 1637 ASSERT(FLAG_allow_absolute_addresses); |
1605 ASSERT(object.IsOld()); | 1638 ASSERT(object.IsOld()); |
1606 // Make sure that class CallPattern is able to decode this load immediate. | 1639 // Make sure that class CallPattern is able to decode this load immediate. |
1607 const int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); | 1640 const int32_t object_raw = reinterpret_cast<int32_t>(object.raw()); |
1608 LoadImmediate(rd, object_raw, cond); | 1641 LoadImmediate(rd, object_raw, cond); |
1609 } | 1642 } |
1610 } | 1643 } |
1611 | 1644 |
1612 | 1645 |
1613 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) { | 1646 void Assembler::LoadObject(Register rd, const Object& object, Condition cond) { |
1614 LoadObjectHelper(rd, object, cond, false); | 1647 LoadObjectHelper(rd, object, cond, /* is_unique = */ false, PP); |
1615 } | 1648 } |
1616 | 1649 |
1617 | 1650 |
1618 void Assembler::LoadUniqueObject(Register rd, | 1651 void Assembler::LoadUniqueObject(Register rd, |
1619 const Object& object, | 1652 const Object& object, |
1620 Condition cond) { | 1653 Condition cond) { |
1621 LoadObjectHelper(rd, object, cond, true); | 1654 LoadObjectHelper(rd, object, cond, /* is_unique = */ true, PP); |
1622 } | 1655 } |
1623 | 1656 |
1624 | 1657 |
1625 void Assembler::LoadExternalLabel(Register rd, | 1658 void Assembler::LoadExternalLabel(Register rd, |
1626 const ExternalLabel* label, | 1659 const ExternalLabel* label, |
1627 Patchability patchable, | 1660 Patchability patchable, |
1628 Condition cond) { | 1661 Condition cond) { |
1629 const int32_t offset = ObjectPool::element_offset( | 1662 const int32_t offset = ObjectPool::element_offset( |
1630 object_pool_wrapper_.FindExternalLabel(label, patchable)); | 1663 object_pool_wrapper_.FindExternalLabel(label, patchable)); |
1631 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); | 1664 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
1632 } | 1665 } |
1633 | 1666 |
1634 | 1667 |
| 1668 void Assembler::LoadFunctionFromCalleePool(Register dst, |
| 1669 const Function& function, |
| 1670 Register new_pp) { |
| 1671 const int32_t offset = |
| 1672 ObjectPool::element_offset(object_pool_wrapper_.FindObject(function)); |
| 1673 LoadWordFromPoolOffset(dst, offset - kHeapObjectTag, new_pp, AL); |
| 1674 } |
| 1675 |
| 1676 |
1635 void Assembler::LoadNativeEntry(Register rd, | 1677 void Assembler::LoadNativeEntry(Register rd, |
1636 const ExternalLabel* label, | 1678 const ExternalLabel* label, |
1637 Patchability patchable, | 1679 Patchability patchable, |
1638 Condition cond) { | 1680 Condition cond) { |
1639 const int32_t offset = ObjectPool::element_offset( | 1681 const int32_t offset = ObjectPool::element_offset( |
1640 object_pool_wrapper_.FindNativeEntry(label, patchable)); | 1682 object_pool_wrapper_.FindNativeEntry(label, patchable)); |
1641 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); | 1683 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
1642 } | 1684 } |
1643 | 1685 |
1644 | 1686 |
1645 void Assembler::PushObject(const Object& object) { | 1687 void Assembler::PushObject(const Object& object) { |
1646 LoadObject(IP, object); | 1688 LoadObject(IP, object); |
1647 Push(IP); | 1689 Push(IP); |
1648 } | 1690 } |
1649 | 1691 |
1650 | 1692 |
1651 void Assembler::CompareObject(Register rn, const Object& object) { | 1693 void Assembler::CompareObject(Register rn, const Object& object) { |
(...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1828 bool can_value_be_smi) { | 1870 bool can_value_be_smi) { |
1829 ASSERT(object != value); | 1871 ASSERT(object != value); |
1830 VerifiedWrite(dest, value, kHeapObjectOrSmi); | 1872 VerifiedWrite(dest, value, kHeapObjectOrSmi); |
1831 Label done; | 1873 Label done; |
1832 if (can_value_be_smi) { | 1874 if (can_value_be_smi) { |
1833 StoreIntoObjectFilter(object, value, &done); | 1875 StoreIntoObjectFilter(object, value, &done); |
1834 } else { | 1876 } else { |
1835 StoreIntoObjectFilterNoSmi(object, value, &done); | 1877 StoreIntoObjectFilterNoSmi(object, value, &done); |
1836 } | 1878 } |
1837 // A store buffer update is required. | 1879 // A store buffer update is required. |
1838 RegList regs = (1 << LR); | 1880 RegList regs = (1 << CODE_REG) | (1 << LR); |
1839 if (value != R0) { | 1881 if (value != R0) { |
1840 regs |= (1 << R0); // Preserve R0. | 1882 regs |= (1 << R0); // Preserve R0. |
1841 } | 1883 } |
1842 PushList(regs); | 1884 PushList(regs); |
1843 if (object != R0) { | 1885 if (object != R0) { |
1844 mov(R0, Operand(object)); | 1886 mov(R0, Operand(object)); |
1845 } | 1887 } |
| 1888 ldr(CODE_REG, Address(THR, Thread::update_store_buffer_code_offset())); |
1846 ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset())); | 1889 ldr(LR, Address(THR, Thread::update_store_buffer_entry_point_offset())); |
1847 blx(LR); | 1890 blx(LR); |
1848 PopList(regs); | 1891 PopList(regs); |
1849 Bind(&done); | 1892 Bind(&done); |
1850 } | 1893 } |
1851 | 1894 |
1852 | 1895 |
1853 void Assembler::StoreIntoObjectOffset(Register object, | 1896 void Assembler::StoreIntoObjectOffset(Register object, |
1854 int32_t offset, | 1897 int32_t offset, |
1855 Register value, | 1898 Register value, |
(...skipping 835 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2691 void Assembler::Vdivqs(QRegister qd, QRegister qn, QRegister qm) { | 2734 void Assembler::Vdivqs(QRegister qd, QRegister qn, QRegister qm) { |
2692 ASSERT(qd != QTMP); | 2735 ASSERT(qd != QTMP); |
2693 ASSERT(qn != QTMP); | 2736 ASSERT(qn != QTMP); |
2694 ASSERT(qm != QTMP); | 2737 ASSERT(qm != QTMP); |
2695 | 2738 |
2696 Vreciprocalqs(qd, qm); | 2739 Vreciprocalqs(qd, qm); |
2697 vmulqs(qd, qn, qd); | 2740 vmulqs(qd, qn, qd); |
2698 } | 2741 } |
2699 | 2742 |
2700 | 2743 |
2701 void Assembler::Branch(const StubEntry& stub_entry, Condition cond) { | 2744 void Assembler::Branch(const StubEntry& stub_entry, |
2702 // Address is never patched. | 2745 Patchability patchable, |
2703 LoadImmediate(IP, stub_entry.label().address(), cond); | 2746 Register pp, |
| 2747 Condition cond) { |
| 2748 const Code& target_code = Code::Handle(stub_entry.code()); |
| 2749 const int32_t offset = ObjectPool::element_offset( |
| 2750 object_pool_wrapper_.FindObject(target_code, patchable)); |
| 2751 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, pp, cond); |
| 2752 ldr(IP, FieldAddress(CODE_REG, Code::entry_point_offset()), cond); |
2704 bx(IP, cond); | 2753 bx(IP, cond); |
2705 } | 2754 } |
2706 | 2755 |
2707 | 2756 |
2708 void Assembler::BranchPatchable(const StubEntry& stub_entry) { | 2757 void Assembler::BranchLink(const Code& target, Patchability patchable) { |
2709 // Use a fixed size code sequence, since a function prologue may be patched | 2758 // Make sure that class CallPattern is able to patch the label referred |
2710 // with this branch sequence. | 2759 // to by this code sequence. |
2711 // Contrarily to BranchLinkPatchable, BranchPatchable requires an instruction | 2760 // For added code robustness, use 'blx lr' in a patchable sequence and |
2712 // cache flush upon patching. | 2761 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). |
2713 LoadPatchableImmediate(IP, stub_entry.label().address()); | 2762 const int32_t offset = ObjectPool::element_offset( |
2714 bx(IP); | 2763 object_pool_wrapper_.FindObject(target, patchable)); |
| 2764 LoadWordFromPoolOffset(CODE_REG, offset - kHeapObjectTag, PP, AL); |
| 2765 ldr(LR, FieldAddress(CODE_REG, Code::entry_point_offset())); |
| 2766 blx(LR); // Use blx instruction so that the return branch prediction works. |
| 2767 } |
| 2768 |
| 2769 |
| 2770 void Assembler::BranchLink(const StubEntry& stub_entry, |
| 2771 Patchability patchable) { |
| 2772 const Code& code = Code::Handle(stub_entry.code()); |
| 2773 BranchLink(code, patchable); |
| 2774 } |
| 2775 |
| 2776 |
| 2777 void Assembler::BranchLinkPatchable(const Code& target) { |
| 2778 BranchLink(target, kPatchable); |
2715 } | 2779 } |
2716 | 2780 |
2717 | 2781 |
2718 void Assembler::BranchLink(const ExternalLabel* label) { | 2782 void Assembler::BranchLink(const ExternalLabel* label) { |
2719 LoadImmediate(LR, label->address()); // Target address is never patched. | 2783 LoadImmediate(LR, label->address()); // Target address is never patched. |
2720 blx(LR); // Use blx instruction so that the return branch prediction works. | 2784 blx(LR); // Use blx instruction so that the return branch prediction works. |
2721 } | 2785 } |
2722 | 2786 |
2723 | 2787 |
2724 void Assembler::BranchLink(const ExternalLabel* label, Patchability patchable) { | 2788 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) { |
2725 // Make sure that class CallPattern is able to patch the label referred | 2789 BranchLinkPatchable(Code::Handle(stub_entry.code())); |
2726 // to by this code sequence. | |
2727 // For added code robustness, use 'blx lr' in a patchable sequence and | |
2728 // use 'blx ip' in a non-patchable sequence (see other BranchLink flavors). | |
2729 const int32_t offset = ObjectPool::element_offset( | |
2730 object_pool_wrapper_.FindExternalLabel(label, patchable)); | |
2731 LoadWordFromPoolOffset(LR, offset - kHeapObjectTag, AL); | |
2732 blx(LR); // Use blx instruction so that the return branch prediction works. | |
2733 } | 2790 } |
2734 | 2791 |
2735 | 2792 |
2736 void Assembler::BranchLink(const StubEntry& stub_entry, | |
2737 Patchability patchable) { | |
2738 BranchLink(&stub_entry.label(), patchable); | |
2739 } | |
2740 | |
2741 | |
2742 void Assembler::BranchLinkPatchable(const StubEntry& stub_entry) { | |
2743 BranchLink(&stub_entry.label(), kPatchable); | |
2744 } | |
2745 | |
2746 | |
2747 void Assembler::BranchLinkOffset(Register base, int32_t offset) { | 2793 void Assembler::BranchLinkOffset(Register base, int32_t offset) { |
2748 ASSERT(base != PC); | 2794 ASSERT(base != PC); |
2749 ASSERT(base != IP); | 2795 ASSERT(base != IP); |
2750 LoadFromOffset(kWord, IP, base, offset); | 2796 LoadFromOffset(kWord, IP, base, offset); |
2751 blx(IP); // Use blx instruction so that the return branch prediction works. | 2797 blx(IP); // Use blx instruction so that the return branch prediction works. |
2752 } | 2798 } |
2753 | 2799 |
2754 | 2800 |
2755 void Assembler::LoadPatchableImmediate( | 2801 void Assembler::LoadPatchableImmediate( |
2756 Register rd, int32_t value, Condition cond) { | 2802 Register rd, int32_t value, Condition cond) { |
(...skipping 17 matching lines...) Expand all Loading... |
2774 } | 2820 } |
2775 } | 2821 } |
2776 | 2822 |
2777 | 2823 |
2778 void Assembler::LoadDecodableImmediate( | 2824 void Assembler::LoadDecodableImmediate( |
2779 Register rd, int32_t value, Condition cond) { | 2825 Register rd, int32_t value, Condition cond) { |
2780 const ARMVersion version = TargetCPUFeatures::arm_version(); | 2826 const ARMVersion version = TargetCPUFeatures::arm_version(); |
2781 if ((version == ARMv5TE) || (version == ARMv6)) { | 2827 if ((version == ARMv5TE) || (version == ARMv6)) { |
2782 if (constant_pool_allowed()) { | 2828 if (constant_pool_allowed()) { |
2783 const int32_t offset = Array::element_offset(FindImmediate(value)); | 2829 const int32_t offset = Array::element_offset(FindImmediate(value)); |
2784 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, cond); | 2830 LoadWordFromPoolOffset(rd, offset - kHeapObjectTag, PP, cond); |
2785 } else { | 2831 } else { |
2786 LoadPatchableImmediate(rd, value, cond); | 2832 LoadPatchableImmediate(rd, value, cond); |
2787 } | 2833 } |
2788 } else { | 2834 } else { |
2789 ASSERT(version == ARMv7); | 2835 ASSERT(version == ARMv7); |
2790 movw(rd, Utils::Low16Bits(value), cond); | 2836 movw(rd, Utils::Low16Bits(value), cond); |
2791 const uint16_t value_high = Utils::High16Bits(value); | 2837 const uint16_t value_high = Utils::High16Bits(value); |
2792 if (value_high != 0) { | 2838 if (value_high != 0) { |
2793 movt(rd, value_high, cond); | 2839 movt(rd, value_high, cond); |
2794 } | 2840 } |
(...skipping 515 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3310 | 3356 |
3311 | 3357 |
3312 void Assembler::CallRuntime(const RuntimeEntry& entry, | 3358 void Assembler::CallRuntime(const RuntimeEntry& entry, |
3313 intptr_t argument_count) { | 3359 intptr_t argument_count) { |
3314 entry.Call(this, argument_count); | 3360 entry.Call(this, argument_count); |
3315 } | 3361 } |
3316 | 3362 |
3317 | 3363 |
3318 void Assembler::EnterDartFrame(intptr_t frame_size) { | 3364 void Assembler::EnterDartFrame(intptr_t frame_size) { |
3319 ASSERT(!constant_pool_allowed()); | 3365 ASSERT(!constant_pool_allowed()); |
3320 const intptr_t offset = CodeSize(); | |
3321 | 3366 |
3322 // Save PC in frame for fast identification of corresponding code. | 3367 // Registers are pushed in descending order: R9 | R10 | R11 | R14. |
3323 // Note that callee-saved registers can be added to the register list. | 3368 EnterFrame((1 << PP) | (1 << CODE_REG) | (1 << FP) | (1 << LR), 0); |
3324 EnterFrame((1 << PP) | (1 << FP) | (1 << LR) | (1 << PC), 0); | |
3325 | |
3326 if (offset != 0) { | |
3327 // Adjust saved PC for any intrinsic code that could have been generated | |
3328 // before a frame is created. Use PP as temp register. | |
3329 ldr(PP, Address(FP, 2 * kWordSize)); | |
3330 AddImmediate(PP, PP, -offset); | |
3331 str(PP, Address(FP, 2 * kWordSize)); | |
3332 } | |
3333 | 3369 |
3334 // Setup pool pointer for this dart function. | 3370 // Setup pool pointer for this dart function. |
3335 LoadPoolPointer(); | 3371 LoadPoolPointer(); |
3336 | 3372 |
3337 // Reserve space for locals. | 3373 // Reserve space for locals. |
3338 AddImmediate(SP, -frame_size); | 3374 AddImmediate(SP, -frame_size); |
3339 } | 3375 } |
3340 | 3376 |
3341 | 3377 |
3342 // On entry to a function compiled for OSR, the caller's frame pointer, the | 3378 // On entry to a function compiled for OSR, the caller's frame pointer, the |
3343 // stack locals, and any copied parameters are already in place. The frame | 3379 // stack locals, and any copied parameters are already in place. The frame |
3344 // pointer is already set up. The PC marker is not correct for the | 3380 // pointer is already set up. The PC marker is not correct for the |
3345 // optimized function and there may be extra space for spill slots to | 3381 // optimized function and there may be extra space for spill slots to |
3346 // allocate. We must also set up the pool pointer for the function. | 3382 // allocate. We must also set up the pool pointer for the function. |
3347 void Assembler::EnterOsrFrame(intptr_t extra_size) { | 3383 void Assembler::EnterOsrFrame(intptr_t extra_size) { |
3348 ASSERT(!constant_pool_allowed()); | 3384 ASSERT(!constant_pool_allowed()); |
3349 // mov(IP, Operand(PC)) loads PC + Instr::kPCReadOffset (8). This may be | |
3350 // different from EntryPointToPcMarkerOffset(). | |
3351 const intptr_t offset = | |
3352 CodeSize() + Instr::kPCReadOffset - EntryPointToPcMarkerOffset(); | |
3353 | |
3354 Comment("EnterOsrFrame"); | 3385 Comment("EnterOsrFrame"); |
3355 mov(IP, Operand(PC)); | 3386 RestoreCodePointer(); |
3356 | |
3357 AddImmediate(IP, -offset); | |
3358 str(IP, Address(FP, kPcMarkerSlotFromFp * kWordSize)); | |
3359 | |
3360 // Setup pool pointer for this dart function. | |
3361 LoadPoolPointer(); | 3387 LoadPoolPointer(); |
3362 | 3388 |
3363 AddImmediate(SP, -extra_size); | 3389 AddImmediate(SP, -extra_size); |
3364 } | 3390 } |
3365 | 3391 |
3366 | 3392 |
3367 void Assembler::LeaveDartFrame() { | 3393 void Assembler::LeaveDartFrame(RestorePP restore_pp) { |
3368 set_constant_pool_allowed(false); | 3394 if (restore_pp == kRestoreCallerPP) { |
3369 LeaveFrame((1 << PP) | (1 << FP) | (1 << LR)); | 3395 ldr(PP, Address(FP, kSavedCallerPpSlotFromFp * kWordSize)); |
3370 // Adjust SP for PC pushed in EnterDartFrame. | 3396 set_constant_pool_allowed(false); |
3371 AddImmediate(SP, kWordSize); | 3397 } |
| 3398 Drop(2); // Drop saved PP, PC marker. |
| 3399 LeaveFrame((1 << FP) | (1 << LR)); |
3372 } | 3400 } |
3373 | 3401 |
3374 | 3402 |
3375 void Assembler::EnterStubFrame() { | 3403 void Assembler::EnterStubFrame() { |
3376 set_constant_pool_allowed(false); | 3404 EnterDartFrame(0); |
3377 // Push 0 as saved PC for stub frames. | |
3378 mov(IP, Operand(LR)); | |
3379 mov(LR, Operand(0)); | |
3380 RegList regs = (1 << PP) | (1 << FP) | (1 << IP) | (1 << LR); | |
3381 EnterFrame(regs, 0); | |
3382 // Setup pool pointer for this stub. | |
3383 LoadPoolPointer(); | |
3384 } | 3405 } |
3385 | 3406 |
3386 | 3407 |
3387 void Assembler::LeaveStubFrame() { | 3408 void Assembler::LeaveStubFrame() { |
3388 LeaveDartFrame(); | 3409 LeaveDartFrame(); |
3389 } | 3410 } |
3390 | 3411 |
3391 | 3412 |
3392 void Assembler::LoadAllocationStatsAddress(Register dest, | 3413 void Assembler::LoadAllocationStatsAddress(Register dest, |
3393 intptr_t cid, | 3414 intptr_t cid, |
(...skipping 280 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3674 | 3695 |
3675 | 3696 |
3676 const char* Assembler::FpuRegisterName(FpuRegister reg) { | 3697 const char* Assembler::FpuRegisterName(FpuRegister reg) { |
3677 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); | 3698 ASSERT((0 <= reg) && (reg < kNumberOfFpuRegisters)); |
3678 return fpu_reg_names[reg]; | 3699 return fpu_reg_names[reg]; |
3679 } | 3700 } |
3680 | 3701 |
3681 } // namespace dart | 3702 } // namespace dart |
3682 | 3703 |
3683 #endif // defined TARGET_ARCH_ARM | 3704 #endif // defined TARGET_ARCH_ARM |
OLD | NEW |