diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 3999beeec2bd3..43c1bc8e5f42d 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -148,56 +148,34 @@ extern "C" void disnm(intptr_t p); // strictly should be 64 bit movz #imm16<<0 // 110___10100 (i.e. requires insn[31:21] == 11010010100) // -class RelocActions { -protected: - typedef int (*reloc_insn)(address insn_addr, address &target); - virtual reloc_insn adrpMem() = 0; - virtual reloc_insn adrpAdd() = 0; - virtual reloc_insn adrpMovk() = 0; - - const address _insn_addr; - const uint32_t _insn; +static uint32_t insn_at(address insn_addr, int n) { + return ((uint32_t*)insn_addr)[n]; +} - static uint32_t insn_at(address insn_addr, int n) { - return ((uint32_t*)insn_addr)[n]; - } - uint32_t insn_at(int n) const { - return insn_at(_insn_addr, n); - } +template +class RelocActions : public AllStatic { public: - RelocActions(address insn_addr) : _insn_addr(insn_addr), _insn(insn_at(insn_addr, 0)) {} - RelocActions(address insn_addr, uint32_t insn) - : _insn_addr(insn_addr), _insn(insn) {} - - virtual int unconditionalBranch(address insn_addr, address &target) = 0; - virtual int conditionalBranch(address insn_addr, address &target) = 0; - virtual int testAndBranch(address insn_addr, address &target) = 0; - virtual int loadStore(address insn_addr, address &target) = 0; - virtual int adr(address insn_addr, address &target) = 0; - virtual int adrp(address insn_addr, address &target, reloc_insn inner) = 0; - virtual int immediate(address insn_addr, address &target) = 0; - virtual void verify(address insn_addr, address &target) = 0; - - int ALWAYSINLINE run(address insn_addr, address &target) { + static int ALWAYSINLINE run(address insn_addr, address &target) { int instructions = 1; + uint32_t insn = insn_at(insn_addr, 0); - uint32_t dispatch = Instruction_aarch64::extract(_insn, 30, 25); + uint32_t dispatch = Instruction_aarch64::extract(insn, 30, 25); switch(dispatch) { case 0b001010: case 0b001011: { - instructions = unconditionalBranch(insn_addr, target); + instructions = T::unconditionalBranch(insn_addr, target); break; } case 0b101010: // Conditional branch (immediate) case 0b011010: { // Compare & branch (immediate) - instructions = conditionalBranch(insn_addr, target); - break; + instructions = T::conditionalBranch(insn_addr, target); + break; } case 0b011011: { - instructions = testAndBranch(insn_addr, target); + instructions = T::testAndBranch(insn_addr, target); break; } case 0b001100: @@ -209,9 +187,9 @@ class RelocActions { case 0b111100: case 0b111110: { // load/store - if ((Instruction_aarch64::extract(_insn, 29, 24) & 0b111011) == 0b011000) { + if ((Instruction_aarch64::extract(insn, 29, 24) & 0b111011) == 0b011000) { // Load register (literal) - instructions = loadStore(insn_addr, target); + instructions = T::loadStore(insn_addr, target); break; } else { // nothing to do @@ -224,27 +202,27 @@ class RelocActions { case 0b101000: case 0b111000: { // adr/adrp - assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be"); - int shift = Instruction_aarch64::extract(_insn, 31, 31); + assert(Instruction_aarch64::extract(insn, 28, 24) == 0b10000, "must be"); + int shift = Instruction_aarch64::extract(insn, 31, 31); if (shift) { - uint32_t insn2 = insn_at(1); + uint32_t insn2 = insn_at(insn_addr, 1); if (Instruction_aarch64::extract(insn2, 29, 24) == 0b111001 && - Instruction_aarch64::extract(_insn, 4, 0) == + Instruction_aarch64::extract(insn, 4, 0) == Instruction_aarch64::extract(insn2, 9, 5)) { - instructions = adrp(insn_addr, target, adrpMem()); + instructions = T::adrp(insn_addr, target, T::adrpMem); } else if (Instruction_aarch64::extract(insn2, 31, 22) == 0b1001000100 && - Instruction_aarch64::extract(_insn, 4, 0) == + Instruction_aarch64::extract(insn, 4, 0) == Instruction_aarch64::extract(insn2, 4, 0)) { - instructions = adrp(insn_addr, target, adrpAdd()); + instructions = T::adrp(insn_addr, target, T::adrpAdd); } else if (Instruction_aarch64::extract(insn2, 31, 21) == 0b11110010110 && - Instruction_aarch64::extract(_insn, 4, 0) == + Instruction_aarch64::extract(insn, 4, 0) == Instruction_aarch64::extract(insn2, 4, 0)) { - instructions = adrp(insn_addr, target, adrpMovk()); + instructions = T::adrp(insn_addr, target, T::adrpMovk); } else { ShouldNotReachHere(); } } else { - instructions = adr(insn_addr, target); + instructions = T::adr(insn_addr, target); } break; } @@ -252,7 +230,7 @@ class RelocActions { case 0b011001: case 0b101001: case 0b111001: { - instructions = immediate(insn_addr, target); + instructions = T::immediate(insn_addr, target); break; } default: { @@ -260,42 +238,36 @@ class RelocActions { } } - verify(insn_addr, target); + T::verify(insn_addr, target); return instructions * NativeInstruction::instruction_size; } }; -class Patcher : public RelocActions { - virtual reloc_insn adrpMem() { return &Patcher::adrpMem_impl; } - virtual reloc_insn adrpAdd() { return &Patcher::adrpAdd_impl; } - virtual reloc_insn adrpMovk() { return &Patcher::adrpMovk_impl; } - +class Patcher : public AllStatic { public: - Patcher(address insn_addr) : RelocActions(insn_addr) {} - - virtual int unconditionalBranch(address insn_addr, address &target) { + static int unconditionalBranch(address insn_addr, address &target) { intptr_t offset = (target - insn_addr) >> 2; Instruction_aarch64::spatch(insn_addr, 25, 0, offset); return 1; } - virtual int conditionalBranch(address insn_addr, address &target) { + static int conditionalBranch(address insn_addr, address &target) { intptr_t offset = (target - insn_addr) >> 2; Instruction_aarch64::spatch(insn_addr, 23, 5, offset); return 1; } - virtual int testAndBranch(address insn_addr, address &target) { + static int testAndBranch(address insn_addr, address &target) { intptr_t offset = (target - insn_addr) >> 2; Instruction_aarch64::spatch(insn_addr, 18, 5, offset); return 1; } - virtual int loadStore(address insn_addr, address &target) { + static int loadStore(address insn_addr, address &target) { intptr_t offset = (target - insn_addr) >> 2; Instruction_aarch64::spatch(insn_addr, 23, 5, offset); return 1; } - virtual int adr(address insn_addr, address &target) { + static int adr(address insn_addr, address &target) { #ifdef ASSERT - assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be"); + assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 28, 24) == 0b10000, "must be"); #endif // PC-rel. addressing ptrdiff_t offset = target - insn_addr; @@ -305,17 +277,18 @@ class Patcher : public RelocActions { Instruction_aarch64::patch(insn_addr, 30, 29, offset_lo); return 1; } - virtual int adrp(address insn_addr, address &target, reloc_insn inner) { + template + static int adrp(address insn_addr, address &target, U inner) { int instructions = 1; #ifdef ASSERT - assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be"); + assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 28, 24) == 0b10000, "must be"); #endif ptrdiff_t offset = target - insn_addr; instructions = 2; precond(inner != nullptr); // Give the inner reloc a chance to modify the target. address adjusted_target = target; - instructions = (*inner)(insn_addr, adjusted_target); + instructions = inner(insn_addr, adjusted_target); uintptr_t pc_page = (uintptr_t)insn_addr >> 12; uintptr_t adr_page = (uintptr_t)adjusted_target >> 12; offset = adr_page - pc_page; @@ -325,7 +298,7 @@ class Patcher : public RelocActions { Instruction_aarch64::patch(insn_addr, 30, 29, offset_lo); return instructions; } - static int adrpMem_impl(address insn_addr, address &target) { + static int adrpMem(address insn_addr, address &target) { uintptr_t dest = (uintptr_t)target; int offset_lo = dest & 0xfff; uint32_t insn2 = insn_at(insn_addr, 1); @@ -334,21 +307,21 @@ class Patcher : public RelocActions { guarantee(((dest >> size) << size) == dest, "misaligned target"); return 2; } - static int adrpAdd_impl(address insn_addr, address &target) { + static int adrpAdd(address insn_addr, address &target) { uintptr_t dest = (uintptr_t)target; int offset_lo = dest & 0xfff; Instruction_aarch64::patch(insn_addr + sizeof (uint32_t), 21, 10, offset_lo); return 2; } - static int adrpMovk_impl(address insn_addr, address &target) { + static int adrpMovk(address insn_addr, address &target) { uintptr_t dest = uintptr_t(target); Instruction_aarch64::patch(insn_addr + sizeof (uint32_t), 20, 5, (uintptr_t)target >> 32); dest = (dest & 0xffffffffULL) | (uintptr_t(insn_addr) & 0xffff00000000ULL); target = address(dest); return 2; } - virtual int immediate(address insn_addr, address &target) { - assert(Instruction_aarch64::extract(_insn, 31, 21) == 0b11010010100, "must be"); + static int immediate(address insn_addr, address &target) { + assert(Instruction_aarch64::extract(insn_at(insn_addr, 0), 31, 21) == 0b11010010100, "must be"); uint64_t dest = (uint64_t)target; // Move wide constant assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch"); @@ -358,7 +331,7 @@ class Patcher : public RelocActions { Instruction_aarch64::patch(insn_addr+8, 20, 5, (dest >>= 16) & 0xffff); return 3; } - virtual void verify(address insn_addr, address &target) { + static void verify(address insn_addr, address &target) { #ifdef ASSERT address address_is = MacroAssembler::target_addr_for_insn(insn_addr); if (!(address_is == target)) { @@ -392,56 +365,54 @@ static bool offset_for(uint32_t insn1, uint32_t insn2, ptrdiff_t &byte_offset) { return false; } -class AArch64Decoder : public RelocActions { - virtual reloc_insn adrpMem() { return &AArch64Decoder::adrpMem_impl; } - virtual reloc_insn adrpAdd() { return &AArch64Decoder::adrpAdd_impl; } - virtual reloc_insn adrpMovk() { return &AArch64Decoder::adrpMovk_impl; } - +class AArch64Decoder : public AllStatic { public: - AArch64Decoder(address insn_addr, uint32_t insn) : RelocActions(insn_addr, insn) {} - virtual int loadStore(address insn_addr, address &target) { - intptr_t offset = Instruction_aarch64::sextract(_insn, 23, 5); + static int loadStore(address insn_addr, address &target) { + intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 23, 5); target = insn_addr + (offset << 2); return 1; } - virtual int unconditionalBranch(address insn_addr, address &target) { - intptr_t offset = Instruction_aarch64::sextract(_insn, 25, 0); + static int unconditionalBranch(address insn_addr, address &target) { + intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 25, 0); target = insn_addr + (offset << 2); return 1; } - virtual int conditionalBranch(address insn_addr, address &target) { - intptr_t offset = Instruction_aarch64::sextract(_insn, 23, 5); + static int conditionalBranch(address insn_addr, address &target) { + intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 23, 5); target = address(((uint64_t)insn_addr + (offset << 2))); return 1; } - virtual int testAndBranch(address insn_addr, address &target) { - intptr_t offset = Instruction_aarch64::sextract(_insn, 18, 5); + static int testAndBranch(address insn_addr, address &target) { + intptr_t offset = Instruction_aarch64::sextract(insn_at(insn_addr, 0), 18, 5); target = address(((uint64_t)insn_addr + (offset << 2))); return 1; } - virtual int adr(address insn_addr, address &target) { + static int adr(address insn_addr, address &target) { // PC-rel. addressing - intptr_t offset = Instruction_aarch64::extract(_insn, 30, 29); - offset |= Instruction_aarch64::sextract(_insn, 23, 5) << 2; + uint32_t insn = insn_at(insn_addr, 0); + intptr_t offset = Instruction_aarch64::extract(insn, 30, 29); + offset |= Instruction_aarch64::sextract(insn, 23, 5) << 2; target = address((uint64_t)insn_addr + offset); return 1; } - virtual int adrp(address insn_addr, address &target, reloc_insn inner) { - assert(Instruction_aarch64::extract(_insn, 28, 24) == 0b10000, "must be"); - intptr_t offset = Instruction_aarch64::extract(_insn, 30, 29); - offset |= Instruction_aarch64::sextract(_insn, 23, 5) << 2; + template + static int adrp(address insn_addr, address &target, U inner) { + uint32_t insn = insn_at(insn_addr, 0); + assert(Instruction_aarch64::extract(insn, 28, 24) == 0b10000, "must be"); + intptr_t offset = Instruction_aarch64::extract(insn, 30, 29); + offset |= Instruction_aarch64::sextract(insn, 23, 5) << 2; int shift = 12; offset <<= shift; uint64_t target_page = ((uint64_t)insn_addr) + offset; target_page &= ((uint64_t)-1) << shift; - uint32_t insn2 = insn_at(1); + uint32_t insn2 = insn_at(insn_addr, 1); target = address(target_page); precond(inner != nullptr); - (*inner)(insn_addr, target); + inner(insn_addr, target); return 2; } - static int adrpMem_impl(address insn_addr, address &target) { + static int adrpMem(address insn_addr, address &target) { uint32_t insn2 = insn_at(insn_addr, 1); // Load/store register (unsigned immediate) ptrdiff_t byte_offset = Instruction_aarch64::extract(insn2, 21, 10); @@ -450,14 +421,14 @@ class AArch64Decoder : public RelocActions { target += byte_offset; return 2; } - static int adrpAdd_impl(address insn_addr, address &target) { + static int adrpAdd(address insn_addr, address &target) { uint32_t insn2 = insn_at(insn_addr, 1); // add (immediate) ptrdiff_t byte_offset = Instruction_aarch64::extract(insn2, 21, 10); target += byte_offset; return 2; } - static int adrpMovk_impl(address insn_addr, address &target) { + static int adrpMovk(address insn_addr, address &target) { uint32_t insn2 = insn_at(insn_addr, 1); uint64_t dest = uint64_t(target); dest = (dest & 0xffff0000ffffffff) | @@ -476,35 +447,33 @@ class AArch64Decoder : public RelocActions { return 2; } } - virtual int immediate(address insn_addr, address &target) { + static int immediate(address insn_addr, address &target) { uint32_t *insns = (uint32_t *)insn_addr; - assert(Instruction_aarch64::extract(_insn, 31, 21) == 0b11010010100, "must be"); + assert(Instruction_aarch64::extract(insns[0], 31, 21) == 0b11010010100, "must be"); // Move wide constant: movz, movk, movk. See movptr(). assert(nativeInstruction_at(insns+1)->is_movk(), "wrong insns in patch"); assert(nativeInstruction_at(insns+2)->is_movk(), "wrong insns in patch"); - target = address(uint64_t(Instruction_aarch64::extract(_insn, 20, 5)) - + (uint64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16) - + (uint64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32)); + target = address(uint64_t(Instruction_aarch64::extract(insns[0], 20, 5)) + + (uint64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16) + + (uint64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32)); assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch"); assert(nativeInstruction_at(insn_addr+8)->is_movk(), "wrong insns in patch"); return 3; } - virtual void verify(address insn_addr, address &target) { + static void verify(address insn_addr, address &target) { } }; address MacroAssembler::target_addr_for_insn(address insn_addr, uint32_t insn) { - AArch64Decoder decoder(insn_addr, insn); address target; - decoder.run(insn_addr, target); + RelocActions::run(insn_addr, target); return target; } // Patch any kind of instruction; there may be several instructions. // Return the total length (in bytes) of the instructions. int MacroAssembler::pd_patch_instruction_size(address insn_addr, address target) { - Patcher patcher(insn_addr); - return patcher.run(insn_addr, target); + return RelocActions::run(insn_addr, target); } int MacroAssembler::patch_oop(address insn_addr, address o) {