mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-01 22:18:23 +00:00
8369211: AArch64: Devirtualize class RelocActions
Reviewed-by: adinn, asmehra
This commit is contained in:
parent
b77b9103c3
commit
9a88d7f468
@ -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;
|
||||
static uint32_t insn_at(address insn_addr, int n) {
|
||||
return ((uint32_t*)insn_addr)[n];
|
||||
}
|
||||
|
||||
const address _insn_addr;
|
||||
const uint32_t _insn;
|
||||
|
||||
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:
|
||||
@ -209,9 +187,9 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
case 0b011001:
|
||||
case 0b101001:
|
||||
case 0b111001: {
|
||||
instructions = immediate(insn_addr, target);
|
||||
instructions = T::immediate(insn_addr, target);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -260,42 +238,36 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public:
|
||||
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;
|
||||
@ -325,7 +298,7 @@ public:
|
||||
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 @@ public:
|
||||
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 @@ public:
|
||||
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<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);
|
||||
@ -450,14 +421,14 @@ public:
|
||||
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 @@ public:
|
||||
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 MacroAssembler::target_addr_for_insn(address insn_addr) {
|
||||
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) {
|
||||
@ -546,11 +515,11 @@ int MacroAssembler::patch_narrow_klass(address insn_addr, narrowKlass n) {
|
||||
return 2 * NativeInstruction::instruction_size;
|
||||
}
|
||||
|
||||
address MacroAssembler::target_addr_for_insn_or_null(address insn_addr, unsigned insn) {
|
||||
if (NativeInstruction::is_ldrw_to_zr(address(&insn))) {
|
||||
address MacroAssembler::target_addr_for_insn_or_null(address insn_addr) {
|
||||
if (NativeInstruction::is_ldrw_to_zr(insn_addr)) {
|
||||
return nullptr;
|
||||
}
|
||||
return MacroAssembler::target_addr_for_insn(insn_addr, insn);
|
||||
return MacroAssembler::target_addr_for_insn(insn_addr);
|
||||
}
|
||||
|
||||
void MacroAssembler::safepoint_poll(Label& slow_path, bool at_return, bool in_nmethod, Register tmp) {
|
||||
|
||||
@ -676,16 +676,8 @@ public:
|
||||
static bool needs_explicit_null_check(intptr_t offset);
|
||||
static bool uses_implicit_null_check(void* address);
|
||||
|
||||
static address target_addr_for_insn(address insn_addr, unsigned insn);
|
||||
static address target_addr_for_insn_or_null(address insn_addr, unsigned insn);
|
||||
static address target_addr_for_insn(address insn_addr) {
|
||||
unsigned insn = *(unsigned*)insn_addr;
|
||||
return target_addr_for_insn(insn_addr, insn);
|
||||
}
|
||||
static address target_addr_for_insn_or_null(address insn_addr) {
|
||||
unsigned insn = *(unsigned*)insn_addr;
|
||||
return target_addr_for_insn_or_null(insn_addr, insn);
|
||||
}
|
||||
static address target_addr_for_insn(address insn_addr);
|
||||
static address target_addr_for_insn_or_null(address insn_addr);
|
||||
|
||||
// Required platform-specific helpers for Label::patch_instructions.
|
||||
// They _shadow_ the declarations in AbstractAssembler, which are undefined.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user