8149415: [AArch64] implement JVMCI CodeInstaller

Reviewed-by: aph, kvn
This commit is contained in:
Christian Thalinger 2016-02-10 11:23:17 -10:00
parent 381b9a329d
commit 98bbb4efa0
7 changed files with 257 additions and 60 deletions

View File

@ -30,39 +30,151 @@
#include "vmreg_aarch64.inline.hpp"
jint CodeInstaller::pd_next_offset(NativeInstruction* inst, jint pc_offset, Handle method, TRAPS) {
Unimplemented();
return 0;
if (inst->is_call() || inst->is_jump() || inst->is_blr()) {
return pc_offset + NativeCall::instruction_size;
} else if (inst->is_general_jump()) {
return pc_offset + NativeGeneralJump::instruction_size;
} else {
JVMCI_ERROR_0("unsupported type of instruction for call site");
}
}
void CodeInstaller::pd_patch_OopConstant(int pc_offset, Handle constant, TRAPS) {
Unimplemented();
address pc = _instructions->start() + pc_offset;
Handle obj = HotSpotObjectConstantImpl::object(constant);
jobject value = JNIHandles::make_local(obj());
if (HotSpotObjectConstantImpl::compressed(constant)) {
int oop_index = _oop_recorder->find_index(value);
RelocationHolder rspec = oop_Relocation::spec(oop_index);
_instructions->relocate(pc, rspec, 1);
Unimplemented();
} else {
NativeMovConstReg* move = nativeMovConstReg_at(pc);
move->set_data((intptr_t) value);
int oop_index = _oop_recorder->find_index(value);
RelocationHolder rspec = oop_Relocation::spec(oop_index);
_instructions->relocate(pc, rspec);
}
}
void CodeInstaller::pd_patch_MetaspaceConstant(int pc_offset, Handle constant, TRAPS) {
Unimplemented();
address pc = _instructions->start() + pc_offset;
if (HotSpotMetaspaceConstantImpl::compressed(constant)) {
narrowKlass narrowOop = record_narrow_metadata_reference(constant, CHECK);
TRACE_jvmci_3("relocating (narrow metaspace constant) at " PTR_FORMAT "/0x%x", p2i(pc), narrowOop);
Unimplemented();
} else {
NativeMovConstReg* move = nativeMovConstReg_at(pc);
Metadata* reference = record_metadata_reference(constant, CHECK);
move->set_data((intptr_t) reference);
TRACE_jvmci_3("relocating (metaspace constant) at " PTR_FORMAT "/" PTR_FORMAT, p2i(pc), p2i(reference));
}
}
void CodeInstaller::pd_patch_DataSectionReference(int pc_offset, int data_offset) {
Unimplemented();
address pc = _instructions->start() + pc_offset;
NativeInstruction* inst = nativeInstruction_at(pc);
if (inst->is_adr_aligned()) {
address dest = _constants->start() + data_offset;
_instructions->relocate(pc, section_word_Relocation::spec((address) dest, CodeBuffer::SECT_CONSTS));
TRACE_jvmci_3("relocating at " PTR_FORMAT " (+%d) with destination at %d", p2i(pc), pc_offset, data_offset);
} else {
JVMCI_ERROR("unknown load or move instruction at " PTR_FORMAT, p2i(pc));
}
}
void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong foreign_call_destination, TRAPS) {
Unimplemented();
address pc = (address) inst;
if (inst->is_call()) {
NativeCall* call = nativeCall_at(pc);
call->set_destination((address) foreign_call_destination);
_instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());
} else if (inst->is_jump()) {
NativeJump* jump = nativeJump_at(pc);
jump->set_jump_destination((address) foreign_call_destination);
_instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
} else if (inst->is_general_jump()) {
NativeGeneralJump* jump = nativeGeneralJump_at(pc);
jump->set_jump_destination((address) foreign_call_destination);
_instructions->relocate(jump->instruction_address(), runtime_call_Relocation::spec());
} else {
JVMCI_ERROR("unknown call or jump instruction at " PTR_FORMAT, p2i(pc));
}
TRACE_jvmci_3("relocating (foreign call) at " PTR_FORMAT, p2i(inst));
}
void CodeInstaller::pd_relocate_JavaMethod(Handle hotspot_method, jint pc_offset, TRAPS) {
Unimplemented();
#ifdef ASSERT
Method* method = NULL;
// we need to check, this might also be an unresolved method
if (hotspot_method->is_a(HotSpotResolvedJavaMethodImpl::klass())) {
method = getMethodFromHotSpotMethod(hotspot_method());
}
#endif
switch (_next_call_type) {
case INLINE_INVOKE:
break;
case INVOKEVIRTUAL:
case INVOKEINTERFACE: {
assert(method == NULL || !method->is_static(), "cannot call static method with invokeinterface");
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
call->set_destination(SharedRuntime::get_resolve_virtual_call_stub());
_instructions->relocate(call->instruction_address(), virtual_call_Relocation::spec(_invoke_mark_pc));
break;
}
case INVOKESTATIC: {
assert(method == NULL || method->is_static(), "cannot call non-static method with invokestatic");
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
call->set_destination(SharedRuntime::get_resolve_static_call_stub());
_instructions->relocate(call->instruction_address(), relocInfo::static_call_type);
break;
}
case INVOKESPECIAL: {
assert(method == NULL || !method->is_static(), "cannot call static method with invokespecial");
NativeCall* call = nativeCall_at(_instructions->start() + pc_offset);
call->set_destination(SharedRuntime::get_resolve_opt_virtual_call_stub());
_instructions->relocate(call->instruction_address(), relocInfo::opt_virtual_call_type);
break;
}
default:
JVMCI_ERROR("invalid _next_call_type value");
break;
}
}
void CodeInstaller::pd_relocate_poll(address pc, jint mark, TRAPS) {
Unimplemented();
switch (mark) {
case POLL_NEAR:
JVMCI_ERROR("unimplemented");
break;
case POLL_FAR:
_instructions->relocate(pc, relocInfo::poll_type);
break;
case POLL_RETURN_NEAR:
JVMCI_ERROR("unimplemented");
break;
case POLL_RETURN_FAR:
_instructions->relocate(pc, relocInfo::poll_return_type);
break;
default:
JVMCI_ERROR("invalid mark value");
break;
}
}
// convert JVMCI register indices (as used in oop maps) to HotSpot registers
VMReg CodeInstaller::get_hotspot_reg(jint jvmci_reg, TRAPS) {
return NULL;
if (jvmci_reg < RegisterImpl::number_of_registers) {
return as_Register(jvmci_reg)->as_VMReg();
} else {
jint floatRegisterNumber = jvmci_reg - RegisterImpl::number_of_registers;
if (floatRegisterNumber < FloatRegisterImpl::number_of_registers) {
return as_FloatRegister(floatRegisterNumber)->as_VMReg();
}
JVMCI_ERROR_NULL("invalid register number: %d", jvmci_reg);
}
}
bool CodeInstaller::is_general_purpose_reg(VMReg hotspotRegister) {
return false;
return !hotspotRegister->is_FloatRegister();
}

View File

@ -136,7 +136,7 @@ void NativeMovConstReg::set_data(intptr_t x) {
MacroAssembler::pd_patch_instruction(instruction_address(), (address)x);
ICache::invalidate_range(instruction_address(), instruction_size);
}
};
}
void NativeMovConstReg::print() {
tty->print_cr(PTR_FORMAT ": mov reg, " INTPTR_FORMAT,
@ -208,6 +208,32 @@ void NativeJump::set_jump_destination(address dest) {
//-------------------------------------------------------------------
address NativeGeneralJump::jump_destination() const {
NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
address dest = (address) move->data();
// We use jump to self as the unresolved address which the inline
// cache code (and relocs) know about
// return -1 if jump to self
dest = (dest == (address) this) ? (address) -1 : dest;
return dest;
}
void NativeGeneralJump::set_jump_destination(address dest) {
NativeMovConstReg* move = nativeMovConstReg_at(instruction_address());
// We use jump to self as the unresolved address which the inline
// cache code (and relocs) know about
if (dest == (address) -1) {
dest = instruction_address();
}
move->set_data((uintptr_t) dest);
};
//-------------------------------------------------------------------
bool NativeInstruction::is_safepoint_poll() {
// a safepoint_poll is implemented in two steps as either
//
@ -249,6 +275,22 @@ bool NativeInstruction::is_ldrw_to_zr(address instr) {
Instruction_aarch64::extract(insn, 4, 0) == 0b11111);
}
bool NativeInstruction::is_general_jump() {
if (is_movz()) {
NativeInstruction* inst1 = nativeInstruction_at(addr_at(instruction_size * 1));
if (inst1->is_movk()) {
NativeInstruction* inst2 = nativeInstruction_at(addr_at(instruction_size * 2));
if (inst2->is_movk()) {
NativeInstruction* inst3 = nativeInstruction_at(addr_at(instruction_size * 3));
if (inst3->is_blr()) {
return true;
}
}
}
}
return false;
}
bool NativeInstruction::is_movz() {
return Instruction_aarch64::extract(int_at(0), 30, 23) == 0b10100101;
}

View File

@ -54,11 +54,22 @@ class NativeInstruction VALUE_OBJ_CLASS_SPEC {
friend class Relocation;
friend bool is_NativeCallTrampolineStub_at(address);
public:
enum { instruction_size = 4 };
enum {
instruction_size = 4
};
juint encoding() const {
return uint_at(0);
}
bool is_blr() const { return (encoding() & 0xfffffc1f) == 0xd63f0000; }
bool is_adr_aligned() const { return (encoding() & 0xff000000) == 0x10000000; } // adr Xn, <label>, where label is aligned to 4 bytes (address of instruction).
inline bool is_nop();
inline bool is_illegal();
inline bool is_return();
bool is_jump();
bool is_general_jump();
inline bool is_jump_or_nop();
inline bool is_cond_jump();
bool is_safepoint_poll();
@ -341,11 +352,15 @@ class NativeMovRegMemPatching: public NativeMovRegMem {
// An interface for accessing/manipulating native leal instruction of form:
// leal reg, [reg + offset]
class NativeLoadAddress: public NativeMovRegMem {
static const bool has_rex = true;
static const int rex_size = 1;
public:
class NativeLoadAddress: public NativeInstruction {
enum AArch64_specific_constants {
instruction_size = 4,
instruction_offset = 0,
data_offset = 0,
next_instruction_offset = 4
};
public:
void verify();
void print ();
@ -398,6 +413,10 @@ public:
data_offset = 0,
next_instruction_offset = 4 * 4
};
address jump_destination() const;
void set_jump_destination(address dest);
static void insert_unconditional(address code_pos, address entry);
static void replace_mt_safe(address instr_addr, address code_buffer);
static void verify();

View File

@ -70,56 +70,64 @@ public class AArch64 extends Architecture {
public static final Register r28 = new Register(28, 28, "r28", CPU);
public static final Register r29 = new Register(29, 29, "r29", CPU);
public static final Register r30 = new Register(30, 30, "r30", CPU);
/*
* r31 is not a general purpose register, but represents either the stackpointer or the
* zero/discard register depending on the instruction. So we represent those two uses as two
* different registers. The register numbers are kept in sync with register_aarch64.hpp and have
* to be sequential, hence we also need a general r31 register here, which is never used.
*/
public static final Register r31 = new Register(31, 31, "r31", CPU);
public static final Register zr = new Register(32, 31, "zr", CPU);
public static final Register sp = new Register(33, 31, "sp", CPU);
public static final Register lr = r30;
public static final Register zr = r31;
public static final Register sp = r31;
// @formatter:off
public static final Register[] cpuRegisters = {
r0, r1, r2, r3, r4, r5, r6, r7,
r8, r9, r10, r11, r12, r13, r14, r15,
r16, r17, r18, r19, r20, r21, r22, r23,
r24, r25, r26, r27, r28, r29, r30, r31
r24, r25, r26, r27, r28, r29, r30, r31,
zr, sp
};
// @formatter:on
public static final RegisterCategory SIMD = new RegisterCategory("SIMD");
// Simd registers
public static final Register v0 = new Register(32, 0, "v0", SIMD);
public static final Register v1 = new Register(33, 1, "v1", SIMD);
public static final Register v2 = new Register(34, 2, "v2", SIMD);
public static final Register v3 = new Register(35, 3, "v3", SIMD);
public static final Register v4 = new Register(36, 4, "v4", SIMD);
public static final Register v5 = new Register(37, 5, "v5", SIMD);
public static final Register v6 = new Register(38, 6, "v6", SIMD);
public static final Register v7 = new Register(39, 7, "v7", SIMD);
public static final Register v8 = new Register(40, 8, "v8", SIMD);
public static final Register v9 = new Register(41, 9, "v9", SIMD);
public static final Register v10 = new Register(42, 10, "v10", SIMD);
public static final Register v11 = new Register(43, 11, "v11", SIMD);
public static final Register v12 = new Register(44, 12, "v12", SIMD);
public static final Register v13 = new Register(45, 13, "v13", SIMD);
public static final Register v14 = new Register(46, 14, "v14", SIMD);
public static final Register v15 = new Register(47, 15, "v15", SIMD);
public static final Register v16 = new Register(48, 16, "v16", SIMD);
public static final Register v17 = new Register(49, 17, "v17", SIMD);
public static final Register v18 = new Register(50, 18, "v18", SIMD);
public static final Register v19 = new Register(51, 19, "v19", SIMD);
public static final Register v20 = new Register(52, 20, "v20", SIMD);
public static final Register v21 = new Register(53, 21, "v21", SIMD);
public static final Register v22 = new Register(54, 22, "v22", SIMD);
public static final Register v23 = new Register(55, 23, "v23", SIMD);
public static final Register v24 = new Register(56, 24, "v24", SIMD);
public static final Register v25 = new Register(57, 25, "v25", SIMD);
public static final Register v26 = new Register(58, 26, "v26", SIMD);
public static final Register v27 = new Register(59, 27, "v27", SIMD);
public static final Register v28 = new Register(60, 28, "v28", SIMD);
public static final Register v29 = new Register(61, 29, "v29", SIMD);
public static final Register v30 = new Register(62, 30, "v30", SIMD);
public static final Register v31 = new Register(63, 31, "v31", SIMD);
public static final Register v0 = new Register(34, 0, "v0", SIMD);
public static final Register v1 = new Register(35, 1, "v1", SIMD);
public static final Register v2 = new Register(36, 2, "v2", SIMD);
public static final Register v3 = new Register(37, 3, "v3", SIMD);
public static final Register v4 = new Register(38, 4, "v4", SIMD);
public static final Register v5 = new Register(39, 5, "v5", SIMD);
public static final Register v6 = new Register(40, 6, "v6", SIMD);
public static final Register v7 = new Register(41, 7, "v7", SIMD);
public static final Register v8 = new Register(42, 8, "v8", SIMD);
public static final Register v9 = new Register(43, 9, "v9", SIMD);
public static final Register v10 = new Register(44, 10, "v10", SIMD);
public static final Register v11 = new Register(45, 11, "v11", SIMD);
public static final Register v12 = new Register(46, 12, "v12", SIMD);
public static final Register v13 = new Register(47, 13, "v13", SIMD);
public static final Register v14 = new Register(48, 14, "v14", SIMD);
public static final Register v15 = new Register(49, 15, "v15", SIMD);
public static final Register v16 = new Register(50, 16, "v16", SIMD);
public static final Register v17 = new Register(51, 17, "v17", SIMD);
public static final Register v18 = new Register(52, 18, "v18", SIMD);
public static final Register v19 = new Register(53, 19, "v19", SIMD);
public static final Register v20 = new Register(54, 20, "v20", SIMD);
public static final Register v21 = new Register(55, 21, "v21", SIMD);
public static final Register v22 = new Register(56, 22, "v22", SIMD);
public static final Register v23 = new Register(57, 23, "v23", SIMD);
public static final Register v24 = new Register(58, 24, "v24", SIMD);
public static final Register v25 = new Register(59, 25, "v25", SIMD);
public static final Register v26 = new Register(60, 26, "v26", SIMD);
public static final Register v27 = new Register(61, 27, "v27", SIMD);
public static final Register v28 = new Register(62, 28, "v28", SIMD);
public static final Register v29 = new Register(63, 29, "v29", SIMD);
public static final Register v30 = new Register(64, 30, "v30", SIMD);
public static final Register v31 = new Register(65, 31, "v31", SIMD);
// @formatter:off
public static final Register[] simdRegisters = {
@ -136,6 +144,7 @@ public class AArch64 extends Architecture {
r8, r9, r10, r11, r12, r13, r14, r15,
r16, r17, r18, r19, r20, r21, r22, r23,
r24, r25, r26, r27, r28, r29, r30, r31,
zr, sp,
v0, v1, v2, v3, v4, v5, v6, v7,
v8, v9, v10, v11, v12, v13, v14, v15,

View File

@ -31,6 +31,7 @@ import static jdk.vm.ci.aarch64.AArch64.r27;
import static jdk.vm.ci.aarch64.AArch64.r28;
import static jdk.vm.ci.aarch64.AArch64.r29;
import static jdk.vm.ci.aarch64.AArch64.r3;
import static jdk.vm.ci.aarch64.AArch64.r31;
import static jdk.vm.ci.aarch64.AArch64.r4;
import static jdk.vm.ci.aarch64.AArch64.r5;
import static jdk.vm.ci.aarch64.AArch64.r6;
@ -45,11 +46,13 @@ import static jdk.vm.ci.aarch64.AArch64.v4;
import static jdk.vm.ci.aarch64.AArch64.v5;
import static jdk.vm.ci.aarch64.AArch64.v6;
import static jdk.vm.ci.aarch64.AArch64.v7;
import static jdk.vm.ci.aarch64.AArch64.zr;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jdk.vm.ci.aarch64.AArch64;
@ -130,16 +133,20 @@ public class AArch64HotSpotRegisterConfig implements RegisterConfig {
public static final Register threadRegister = r28;
public static final Register fp = r29;
private static final Register[] reservedRegisters = {threadRegister, fp, lr, r31, zr, sp};
private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
Register[] allRegisters = arch.getAvailableValueRegisters();
Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 5 : 4)];
Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
int idx = 0;
for (Register reg : allRegisters) {
if (reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(sp)) {
// skip thread register, frame pointer, link register and stack pointer
if (reservedRegistersList.contains(reg)) {
// skip reserved registers
continue;
}
assert !(reg.equals(threadRegister) || reg.equals(fp) || reg.equals(lr) || reg.equals(r31) || reg.equals(zr) || reg.equals(sp));
if (reserveForHeapBase && reg.equals(heapBaseRegister)) {
// skip heap base register
continue;

View File

@ -45,6 +45,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import jdk.vm.ci.code.Architecture;
@ -119,14 +120,17 @@ public class AMD64HotSpotRegisterConfig implements RegisterConfig {
*/
private final boolean needsNativeStackHomeSpace;
private static final Register[] reservedRegisters = {rsp, r15};
private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
Register[] allRegisters = arch.getAvailableValueRegisters();
Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 3 : 2)];
Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
int idx = 0;
for (Register reg : allRegisters) {
if (reg.equals(rsp) || reg.equals(r15)) {
// skip stack pointer and thread register
if (reservedRegistersList.contains(reg)) {
// skip reserved registers
continue;
}
if (reserveForHeapBase && reg.equals(r12)) {

View File

@ -68,6 +68,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import jdk.vm.ci.code.Architecture;
import jdk.vm.ci.code.CallingConvention;
@ -140,14 +141,17 @@ public class SPARCHotSpotRegisterConfig implements RegisterConfig {
i0, i1, i2, i3, i4, i5, i6, i7};
// @formatter:on
private static final Register[] reservedRegisters = {sp, g0, g2};
private static Register[] initAllocatable(Architecture arch, boolean reserveForHeapBase) {
Register[] allRegisters = arch.getAvailableValueRegisters();
Register[] registers = new Register[allRegisters.length - (reserveForHeapBase ? 4 : 3)];
Register[] registers = new Register[allRegisters.length - reservedRegisters.length - (reserveForHeapBase ? 1 : 0)];
List<Register> reservedRegistersList = Arrays.asList(reservedRegisters);
int idx = 0;
for (Register reg : allRegisters) {
if (reg.equals(sp) || reg.equals(g2) || reg.equals(g0)) {
// skip g0, stack pointer and thread register
if (reservedRegistersList.contains(reg)) {
// skip reserved registers
continue;
}
if (reserveForHeapBase && reg.equals(g6)) {