Index: src/arm64/assembler-arm64.cc |
diff --git a/src/arm64/assembler-arm64.cc b/src/arm64/assembler-arm64.cc |
index 93d1d25a6c7747628d51c0c4466432ad9e749fd8..d0724336333d87476e610c65a9bc2796ffabb4f3 100644 |
--- a/src/arm64/assembler-arm64.cc |
+++ b/src/arm64/assembler-arm64.cc |
@@ -171,7 +171,7 @@ CPURegList CPURegList::GetSafepointSavedRegisters() { |
// ----------------------------------------------------------------------------- |
// Implementation of RelocInfo |
-const int RelocInfo::kApplyMask = 0; |
+const int RelocInfo::kApplyMask = 1 << RelocInfo::INTERNAL_REFERENCE; |
bool RelocInfo::IsCodedSpecially() { |
@@ -732,7 +732,15 @@ void Assembler::bind(Label* label) { |
DCHECK(prevlinkoffset >= 0); |
// Update the link to point to the label. |
- link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_)); |
+ if (link->IsUnresolvedInternalReference()) { |
+ // Internal references do not get patched to an instruction but directly |
+ // to an address. |
+ internal_reference_positions_.push_back(linkoffset); |
+ PatchingAssembler patcher(link, 2); |
+ patcher.dc64(reinterpret_cast<uintptr_t>(pc_)); |
+ } else { |
+ link->SetImmPCOffsetTarget(reinterpret_cast<Instruction*>(pc_)); |
+ } |
// Link the label to the previous link in the chain. |
if (linkoffset - prevlinkoffset == kStartOfLabelLinkChain) { |
@@ -2060,6 +2068,50 @@ void Assembler::ucvtf(const FPRegister& fd, |
} |
+void Assembler::dcptr(Label* label) { |
+ RecordRelocInfo(RelocInfo::INTERNAL_REFERENCE); |
+ if (label->is_bound()) { |
+ // The label is bound, so it does not need to be updated and the internal |
+ // reference should be emitted. |
+ // |
+ // In this case, label->pos() returns the offset of the label from the |
+ // start of the buffer. |
+ internal_reference_positions_.push_back(pc_offset()); |
+ dc64(reinterpret_cast<uintptr_t>(buffer_ + label->pos())); |
+ } else { |
+ int32_t offset; |
+ if (label->is_linked()) { |
+ // The label is linked, so the internal reference should be added |
+ // onto the end of the label's link chain. |
+ // |
+ // In this case, label->pos() returns the offset of the last linked |
+ // instruction from the start of the buffer. |
+ offset = label->pos() - pc_offset(); |
+ DCHECK(offset != kStartOfLabelLinkChain); |
+ } else { |
+ // The label is unused, so it now becomes linked and the internal |
+ // reference is at the start of the new link chain. |
+ offset = kStartOfLabelLinkChain; |
+ } |
+ // The instruction at pc is now the last link in the label's chain. |
+ label->link_to(pc_offset()); |
+ |
+ // Traditionally the offset to the previous instruction in the chain is |
+ // encoded in the instruction payload (e.g. branch range) but internal |
+ // references are not instructions so while unbound they are encoded as |
+ // two consecutive brk instructions. The two 16-bit immediates are used |
+ // to encode the offset. |
+ offset >>= kInstructionSizeLog2; |
+ DCHECK(is_int32(offset)); |
+ uint32_t high16 = unsigned_bitextract_32(31, 16, offset); |
+ uint32_t low16 = unsigned_bitextract_32(15, 0, offset); |
+ |
+ brk(high16); |
+ brk(low16); |
+ } |
+} |
+ |
+ |
// Note: |
// Below, a difference in case for the same letter indicates a |
// negated bit. |
@@ -2819,6 +2871,12 @@ void Assembler::GrowBuffer() { |
// buffer nor pc absolute pointing inside the code buffer, so there is no need |
// to relocate any emitted relocation entries. |
+ // Relocate internal references. |
+ for (auto pos : internal_reference_positions_) { |
+ intptr_t* p = reinterpret_cast<intptr_t*>(buffer_ + pos); |
+ *p += pc_delta; |
+ } |
+ |
// Pending relocation entries are also relative, no need to relocate. |
} |
@@ -2828,6 +2886,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
RelocInfo rinfo(reinterpret_cast<byte*>(pc_), rmode, data, NULL); |
if (((rmode >= RelocInfo::JS_RETURN) && |
(rmode <= RelocInfo::DEBUG_BREAK_SLOT)) || |
+ (rmode == RelocInfo::INTERNAL_REFERENCE) || |
(rmode == RelocInfo::CONST_POOL) || |
(rmode == RelocInfo::VENEER_POOL) || |
(rmode == RelocInfo::DEOPT_REASON)) { |
@@ -2837,6 +2896,7 @@ void Assembler::RecordRelocInfo(RelocInfo::Mode rmode, intptr_t data) { |
|| RelocInfo::IsComment(rmode) |
|| RelocInfo::IsDeoptReason(rmode) |
|| RelocInfo::IsPosition(rmode) |
+ || RelocInfo::IsInternalReference(rmode) |
|| RelocInfo::IsConstPool(rmode) |
|| RelocInfo::IsVeneerPool(rmode)); |
// These modes do not need an entry in the constant pool. |