diff options
Diffstat (limited to 'src/cpu/aarch64/vm/macroAssembler_aarch64.cpp')
-rw-r--r-- | src/cpu/aarch64/vm/macroAssembler_aarch64.cpp | 124 |
1 files changed, 72 insertions, 52 deletions
diff --git a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp index 0b308f2b1..3f9c85ef0 100644 --- a/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp +++ b/src/cpu/aarch64/vm/macroAssembler_aarch64.cpp @@ -65,6 +65,7 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") void MacroAssembler::pd_patch_instruction(address branch, address target) { + assert((uint64_t)target < (1ul << 48), "48-bit overflow in address constant"); long offset = (target - branch) >> 2; unsigned insn = *(unsigned*)branch; if ((Instruction_aarch64::extract(insn, 29, 24) & 0b111011) == 0b011000) { @@ -136,13 +137,15 @@ void MacroAssembler::pd_patch_instruction(address branch, address target) { offset >>= 2; Instruction_aarch64::spatch(branch, 23, 5, offset); Instruction_aarch64::patch(branch, 30, 29, offset_lo); - } else if (Instruction_aarch64::extract(insn, 31, 23) == 0b110100101) { - // Move wide constant + } else if (Instruction_aarch64::extract(insn, 31, 21) == 0b11010010100) { u_int64_t dest = (u_int64_t)target; + // Move wide constant + assert(nativeInstruction_at(branch+4)->is_movk(), "wrong insns in patch"); + assert(nativeInstruction_at(branch+8)->is_movk(), "wrong insns in patch"); Instruction_aarch64::patch(branch, 20, 5, dest & 0xffff); - Instruction_aarch64::patch(branch += 4, 20, 5, (dest >>= 16) & 0xffff); - Instruction_aarch64::patch(branch += 4, 20, 5, (dest >>= 16) & 0xffff); - Instruction_aarch64::patch(branch += 4, 20, 5, (dest >>= 16)); + Instruction_aarch64::patch(branch+4, 20, 5, (dest >>= 16) & 0xffff); + Instruction_aarch64::patch(branch+8, 20, 5, (dest >>= 16) & 0xffff); + assert(pd_call_destination(branch) == target, "should be"); } else if (Instruction_aarch64::extract(insn, 31, 22) == 0b1011100101 && Instruction_aarch64::extract(insn, 4, 0) == 0b11111) { // nothing to do @@ -152,6 +155,19 @@ void MacroAssembler::pd_patch_instruction(address branch, address target) { } } +void MacroAssembler::patch_oop(address insn_addr, address o) { + unsigned insn = *(unsigned*)insn_addr; + if (Instruction_aarch64::extract(insn, 31, 21) == 0b11010010101) { + // Move narrow constant + assert(nativeInstruction_at(insn_addr+4)->is_movk(), "wrong insns in patch"); + narrowOop n = oopDesc::encode_heap_oop((oop)o); + Instruction_aarch64::patch(insn_addr, 20, 5, n >> 16); + Instruction_aarch64::patch(insn_addr+4, 20, 5, n & 0xffff); + } else { + pd_patch_instruction(insn_addr, o); + } +} + address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { long offset = 0; if ((Instruction_aarch64::extract(insn, 29, 24) & 0b011011) == 0b00011000) { @@ -216,14 +232,13 @@ address MacroAssembler::target_addr_for_insn(address insn_addr, unsigned insn) { ShouldNotReachHere(); } } else if (Instruction_aarch64::extract(insn, 31, 23) == 0b110100101) { - // Move wide constant - // FIXME: We assume these instructions are movz, movk, movk, movk. - // We don't assert this; we should. u_int32_t *insns = (u_int32_t *)insn_addr; + // 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"); return address(u_int64_t(Instruction_aarch64::extract(insns[0], 20, 5)) + (u_int64_t(Instruction_aarch64::extract(insns[1], 20, 5)) << 16) - + (u_int64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32) - + (u_int64_t(Instruction_aarch64::extract(insns[3], 20, 5)) << 48)); + + (u_int64_t(Instruction_aarch64::extract(insns[2], 20, 5)) << 32)); } else if (Instruction_aarch64::extract(insn, 31, 22) == 0b1011100101 && Instruction_aarch64::extract(insn, 4, 0) == 0b11111) { return 0; @@ -607,9 +622,10 @@ void MacroAssembler::call(Address entry) { void MacroAssembler::ic_call(address entry) { RelocationHolder rh = virtual_call_Relocation::spec(pc()); - address const_ptr = long_constant((jlong)Universe::non_oop_word()); - unsigned long offset; - ldr_constant(rscratch2, const_ptr); + // address const_ptr = long_constant((jlong)Universe::non_oop_word()); + // unsigned long offset; + // ldr_constant(rscratch2, const_ptr); + movptr(rscratch2, (uintptr_t)Universe::non_oop_word()); call(Address(entry, rh)); } @@ -1246,10 +1262,14 @@ void MacroAssembler::mov(Register r, Address dest) { InstructionMark im(this); code_section()->relocate(inst_mark(), dest.rspec()); u_int64_t imm64 = (u_int64_t)dest.target(); - mov64(r, imm64); + movptr(r, imm64); } -void MacroAssembler::mov64(Register r, uintptr_t imm64) { +// Move a constant pointer into r. In AArch64 mode the virtual +// address space is 48 bits in size, so we only need three +// instructions to create a patchable instruction sequence that can +// reach anywhere. +void MacroAssembler::movptr(Register r, uintptr_t imm64) { #ifndef PRODUCT { char buffer[64]; @@ -1257,13 +1277,12 @@ void MacroAssembler::mov64(Register r, uintptr_t imm64) { block_comment(buffer); } #endif + assert(imm64 < (1ul << 48), "48-bit overflow in address constant"); movz(r, imm64 & 0xffff); imm64 >>= 16; movk(r, imm64 & 0xffff, 16); imm64 >>= 16; movk(r, imm64 & 0xffff, 32); - imm64 >>= 16; - movk(r, imm64 & 0xffff, 48); } void MacroAssembler::mov_immediate64(Register dst, u_int64_t imm64) @@ -2704,29 +2723,33 @@ void MacroAssembler::decode_klass_not_null(Register r) { decode_klass_not_null(r, r); } -// TODO -// -// these next two methods load a narrow oop or klass constant into a -// register. they currently do the dumb thing of installing 64 bits of -// unencoded constant into the register and then encoding it. -// installing the encoded 32 bit constant directly requires updating -// the relocation code so it can recognize that this is a 32 bit load -// rather than a 64 bit load. - void MacroAssembler::set_narrow_oop(Register dst, jobject obj) { - assert (UseCompressedOops, "should only be used for compressed headers"); + assert (UseCompressedOops, "should only be used for compressed oops"); assert (Universe::heap() != NULL, "java heap should be initialized"); assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); - movoop(dst, obj); - encode_heap_oop_not_null(dst); -} + int oop_index = oop_recorder()->find_index(obj); + assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(obj)), "should be real oop"); + + InstructionMark im(this); + RelocationHolder rspec = oop_Relocation::spec(oop_index); + code_section()->relocate(inst_mark(), rspec); + movz(dst, 0xDEAD, 16); + movk(dst, 0xBEEF); +} void MacroAssembler::set_narrow_klass(Register dst, Klass* k) { assert (UseCompressedClassPointers, "should only be used for compressed headers"); assert (oop_recorder() != NULL, "this assembler needs an OopRecorder"); - mov_metadata(dst, k); - encode_klass_not_null(dst); + int index = oop_recorder()->find_index(k); + assert(! Universe::heap()->is_in_reserved(k), "should not be an oop"); + + InstructionMark im(this); + RelocationHolder rspec = metadata_Relocation::spec(index); + code_section()->relocate(inst_mark(), rspec); + narrowKlass nk = Klass::encode_klass(k); + movz(dst, (nk >> 16), 16); + movk(dst, nk & 0xffff); } void MacroAssembler::load_heap_oop(Register dst, Address src) @@ -2736,7 +2759,7 @@ void MacroAssembler::load_heap_oop(Register dst, Address src) decode_heap_oop(dst); } else { ldr(dst, src); - } + } } void MacroAssembler::load_heap_oop_not_null(Register dst, Address src) @@ -2948,7 +2971,11 @@ Address MacroAssembler::allocate_metadata_address(Metadata* obj) { return Address((address)obj, rspec); } -void MacroAssembler::movoop(Register dst, jobject obj) { +// Move an oop into a register. immediate is true if we want +// immediate instrcutions, i.e. we are not going to patch this +// instruction while the code is being executed by another thread. In +// that case we can use move immediates rather than the constant pool. +void MacroAssembler::movoop(Register dst, jobject obj, bool immediate) { int oop_index; if (obj == NULL) { oop_index = oop_recorder()->allocate_oop_index(obj); @@ -2957,15 +2984,14 @@ void MacroAssembler::movoop(Register dst, jobject obj) { assert(Universe::heap()->is_in_reserved(JNIHandles::resolve(obj)), "should be real oop"); } RelocationHolder rspec = oop_Relocation::spec(oop_index); - address const_ptr = long_constant((jlong)obj); - if (! const_ptr) { + if (! immediate) { + address dummy = address(uintptr_t(pc()) & -wordSize); // A nearby aligned address + ldr_constant(dst, Address(dummy, rspec)); + } else mov(dst, Address((address)obj, rspec)); - } else { - code()->consts()->relocate(const_ptr, rspec); - ldr_constant(dst, const_ptr); - } } +// Move a metadata address into a register. void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { int oop_index; if (obj == NULL) { @@ -2974,13 +3000,7 @@ void MacroAssembler::mov_metadata(Register dst, Metadata* obj) { oop_index = oop_recorder()->find_index(obj); } RelocationHolder rspec = metadata_Relocation::spec(oop_index); - address const_ptr = long_constant((jlong)obj); - if (! const_ptr) { - mov(dst, Address((address)obj, rspec)); - } else { - code()->consts()->relocate(const_ptr, rspec); - ldr_constant(dst, const_ptr); - } + mov(dst, Address((address)obj, rspec)); } Address MacroAssembler::constant_oop_address(jobject obj) { @@ -3268,12 +3288,12 @@ address MacroAssembler::read_polling_page(Register r, relocInfo::relocType rtype void MacroAssembler::adrp(Register reg1, const Address &dest, unsigned long &byte_offset) { relocInfo::relocType rtype = dest.rspec().reloc()->type(); - guarantee(rtype == relocInfo::none - || rtype == relocInfo::external_word_type - || rtype == relocInfo::poll_type - || rtype == relocInfo::poll_return_type, - "can only use a fixed address with an ADRP"); if (labs(pc() - dest.target()) >= (1LL << 32)) { + guarantee(rtype == relocInfo::none + || rtype == relocInfo::external_word_type + || rtype == relocInfo::poll_type + || rtype == relocInfo::poll_return_type, + "can only use a fixed address with an ADRP"); // Out of range. This doesn't happen very often, but we have to // handle it mov(reg1, dest); |