Index: src/arm64/instructions-arm64.cc |
diff --git a/src/arm64/instructions-arm64.cc b/src/arm64/instructions-arm64.cc |
index 71094baa8788f9d995b5ae62c54f5c50f1049dfd..7a5effe427847582dd71e3bff9e14a29e97edca2 100644 |
--- a/src/arm64/instructions-arm64.cc |
+++ b/src/arm64/instructions-arm64.cc |
@@ -191,6 +191,9 @@ int64_t Instruction::ImmPCOffset() { |
// All PC-relative branches. |
// Relative branch offsets are instruction-size-aligned. |
offset = ImmBranch() << kInstructionSizeLog2; |
+ } else if (IsUnresolvedInternalReference()) { |
+ // Internal references are always word-aligned. |
+ offset = ImmUnresolvedInternalReference() << kInstructionSizeLog2; |
} else { |
// Load literal (offset from PC). |
DCHECK(IsLdrLiteral()); |
@@ -223,7 +226,10 @@ void Instruction::SetImmPCOffsetTarget(Instruction* target) { |
SetPCRelImmTarget(target); |
} else if (BranchType() != UnknownBranchType) { |
SetBranchImmTarget(target); |
+ } else if (IsUnresolvedInternalReference()) { |
+ SetUnresolvedInternalReferenceImmTarget(target); |
} else { |
+ // Load literal (offset from PC). |
SetImmLLiteral(target); |
} |
} |
@@ -278,7 +284,23 @@ void Instruction::SetBranchImmTarget(Instruction* target) { |
} |
+void Instruction::SetUnresolvedInternalReferenceImmTarget(Instruction* target) { |
+ DCHECK(IsUnresolvedInternalReference()); |
+ DCHECK(IsAligned(DistanceTo(target), kInstructionSize)); |
+ |
+ ptrdiff_t target_offset = DistanceTo(target) >> kInstructionSizeLog2; |
+ DCHECK(is_int32(target_offset)); |
+ uint32_t high16 = unsigned_bitextract_32(31, 16, target_offset); |
+ uint32_t low16 = unsigned_bitextract_32(15, 0, target_offset); |
+ |
+ PatchingAssembler patcher(this, 2); |
+ patcher.brk(high16); |
+ patcher.brk(low16); |
+} |
+ |
+ |
void Instruction::SetImmLLiteral(Instruction* source) { |
+ DCHECK(IsLdrLiteral()); |
DCHECK(IsAligned(DistanceTo(source), kInstructionSize)); |
ptrdiff_t offset = DistanceTo(source) >> kLoadLiteralScaleLog2; |
Instr imm = Assembler::ImmLLiteral(offset); |