Index: src/arm64/assembler-arm64.cc |
diff --git a/src/arm64/assembler-arm64.cc b/src/arm64/assembler-arm64.cc |
index 8bee92ccc273a87b1e319481ef0697063c7f4075..2e3c5492164a40663ee55c85862316cbb4e333c5 100644 |
--- a/src/arm64/assembler-arm64.cc |
+++ b/src/arm64/assembler-arm64.cc |
@@ -2808,6 +2808,76 @@ void Assembler::PopulateConstantPool(ConstantPoolArray* constant_pool) { |
} |
+void PatchingAssembler::MovInt64(const Register& rd, int64_t imm) { |
+ Label start; |
+ bind(&start); |
+ |
+ ASSERT(rd.Is64Bits()); |
+ ASSERT(!rd.IsSP()); |
+ |
+ for (unsigned i = 0; i < (rd.SizeInBits() / 16); i++) { |
+ uint64_t imm16 = (imm >> (16 * i)) & 0xffffL; |
+ movk(rd, imm16, 16 * i); |
+ } |
+ |
+ ASSERT(SizeOfCodeGeneratedSince(&start) == |
+ kMovInt64NInstrs * kInstructionSize); |
+} |
+ |
+ |
+void PatchingAssembler::PatchAdrFar(Instruction* target) { |
+ // The code at the current instruction should be: |
+ // adr rd, 0 |
+ // nop (adr_far) |
+ // nop (adr_far) |
+ // nop (adr_far) |
+ // movz scratch, 0 |
+ // add rd, rd, scratch |
+ |
+ // Verify the expected code. |
+ Instruction* expected_adr = InstructionAt(0); |
+ CHECK(expected_adr->IsAdr() && (expected_adr->ImmPCRel() == 0)); |
+ int rd_code = expected_adr->Rd(); |
+ for (int i = 0; i < kAdrFarPatchableNNops; ++i) { |
+ CHECK(InstructionAt((i + 1) * kInstructionSize)->IsNop(ADR_FAR_NOP)); |
+ } |
+ Instruction* expected_movz = |
+ InstructionAt((kAdrFarPatchableNInstrs - 2) * kInstructionSize); |
+ CHECK(expected_movz->IsMovz() && |
+ (expected_movz->ImmMoveWide() == 0) && |
+ (expected_movz->ShiftMoveWide() == 0)); |
+ int scratch_code = expected_movz->Rd(); |
+ Instruction* expected_add = |
+ InstructionAt((kAdrFarPatchableNInstrs - 1) * kInstructionSize); |
+ CHECK(expected_add->IsAddSubShifted() && |
+ (expected_add->Mask(AddSubOpMask) == ADD) && |
+ expected_add->SixtyFourBits() && |
+ (expected_add->Rd() == rd_code) && (expected_add->Rn() == rd_code) && |
+ (expected_add->Rm() == scratch_code) && |
+ (static_cast<Shift>(expected_add->ShiftDP()) == LSL) && |
+ (expected_add->ImmDPShift() == 0)); |
+ |
+ // Patch to load the correct address. |
+ Label start; |
+ bind(&start); |
+ Register rd = Register::XRegFromCode(rd_code); |
+ // If the target is in range, we only patch the adr. Otherwise we patch the |
+ // nops with fixup instructions. |
+ int target_offset = expected_adr->DistanceTo(target); |
+ if (Instruction::IsValidPCRelOffset(target_offset)) { |
+ adr(rd, target_offset); |
+ for (int i = 0; i < kAdrFarPatchableNInstrs - 2; ++i) { |
+ nop(ADR_FAR_NOP); |
+ } |
+ } else { |
+ Register scratch = Register::XRegFromCode(scratch_code); |
+ adr(rd, 0); |
+ MovInt64(scratch, target_offset); |
+ add(rd, rd, scratch); |
+ } |
+} |
+ |
+ |
} } // namespace v8::internal |
#endif // V8_TARGET_ARCH_ARM64 |