Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 75 additions & 106 deletions src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T>
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:
Expand All @@ -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
Expand All @@ -224,78 +202,72 @@ 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;
}
case 0b001001:
case 0b011001:
case 0b101001:
case 0b111001: {
instructions = immediate(insn_addr, target);
instructions = T::immediate(insn_addr, target);
break;
}
default: {
ShouldNotReachHere();
}
}

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;
Expand All @@ -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<typename U>
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;
Expand All @@ -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);
Expand All @@ -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");
Expand All @@ -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)) {
Expand Down Expand Up @@ -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<typename U>
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);
Expand All @@ -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) |
Expand All @@ -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<AArch64Decoder>::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<Patcher>::run(insn_addr, target);
}

int MacroAssembler::patch_oop(address insn_addr, address o) {
Expand Down