diff --git a/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp b/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp index a9e141e7e4099..784b29b5f7493 100644 --- a/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp +++ b/src/hotspot/cpu/riscv/jvmciCodeInstaller_riscv.cpp @@ -83,9 +83,9 @@ void CodeInstaller::pd_relocate_ForeignCall(NativeInstruction* inst, jlong forei address pc = (address) inst; if (inst->is_jal()) { assert(false, "Bad"); -/* NativeCall* call = nativeCall_at(pc); + NativeCall* call = nativeCall_at(pc); call->set_destination((address) foreign_call_destination); - _instructions->relocate(call->instruction_address(), runtime_call_Relocation::spec());*/ + _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); diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp index 7da09a0e326c6..8ac16e2877459 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.cpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.cpp @@ -39,6 +39,8 @@ #include "c1/c1_Runtime1.hpp" #endif +//----------------------------------------------------------------------------- +// NativeInstruction Register NativeInstruction::extract_rs1(address instr) { assert_cond(instr != nullptr); return as_Register(Assembler::extract(Assembler::ld_instr(instr), 19, 15)); @@ -120,11 +122,81 @@ bool NativeInstruction::is_li64_at(address instr) { check_li64_data_dependency(instr); } -void NativeCall::verify() { - assert(is_load_pc_relative_at(instruction_address()), "unexpected code at call site: %p", (address)this); +//----------------------------------------------------------------------------- +// NativeShortCall + +address NativeShortCall::destination() const { + address addr = (address)this; + assert(NativeShortCall::is_at(addr), "unexpected code at call site"); + assert(NativeInstruction::is_jal_at(instruction_address()), "inst must be jal."); + address destination = MacroAssembler::target_addr_for_insn(instruction_address()); + return destination; } -address NativeCall::destination() const { +void NativeShortCall::set_destination(address dest) { + assert(NativeShortCall::is_at((address)this), "unexpected code at call site"); +} + +void NativeShortCall::verify() { + assert(NativeShortCall::is_at((address)this), "unexpected code at call site"); +} + +void NativeShortCall::print() { + assert(NativeShortCall::is_at((address)this), "unexpected code at call site"); + tty->print_cr(PTR_FORMAT ": jal/auipc,ld,jalr x1, offset/reg", p2i(instruction_address())); +} + +void NativeShortCall::set_destination_mt_safe(address dest, bool assert_lock) { + assert(NativeShortCall::is_at((address)this), "unexpected code at call site"); + assert(!assert_lock || + (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || + CompiledICLocker::is_safe(addr_at(0)), + "concurrent code patching"); + + address addr_call = addr_at(0); + // Patch the call. + assert(Assembler::reachable_from_branch_at(addr_call, dest), "we need a trampoline"); + set_destination(dest); + + ICache::invalidate_range(addr_call, instruction_size); +} + +NativeShortCall* NativeShortCall::at(address addr) { + assert_cond(addr != nullptr); + assert(NativeShortCall::is_at(addr), "unexpected code at call site"); + NativeShortCall* call = (NativeShortCall*)(addr); + return call; +} + +bool NativeShortCall::is_at(address addr) { + assert(!is_jalr_at(addr), "What?"); + if (is_jal_at(addr)) { + if (NativeInstruction::extract_rd(addr) == x1) { + return true; + } + } + return false; +} + +bool NativeShortCall::is_call_before(address return_address) { + assert(NativeShortCall::is_at(return_address - Assembler::instruction_size), "unexpected code at call site"); + return false; +} + +void NativeShortCall::insert(address code_pos, address entry) { + Unimplemented(); +} + +void NativeShortCall::replace_mt_safe(address instr_addr, address code_buffer) { + Unimplemented(); +} + +//----------------------------------------------------------------------------- +// NativeFarCall + +address NativeFarCall::destination() const { + assert(NativeFarCall::is_at((address)this), "unexpected code at call site"); + address addr = (address)this; assert(is_load_pc_relative_at(instruction_address()), "Must be"); address destination = MacroAssembler::target_addr_for_insn(instruction_address()); @@ -133,75 +205,153 @@ address NativeCall::destination() const { CodeBlob* cb = CodeCache::find_blob(addr); assert(cb && cb->is_nmethod(), "sanity"); nmethod *nm = (nmethod *)cb; - if (nm != nullptr && nm->stub_contains(destination) && is_NativeCallTrampolineStub_at(destination)) { - // Yes we do, so get the destination from the trampoline stub. - const address trampoline_stub_addr = destination; - destination = nativeCallTrampolineStub_at(trampoline_stub_addr)->destination(); - } + assert(nm != nullptr && nm->stub_contains(destination), "No tramp"); + assert(is_NativeCallTrampolineStub_at(destination), "Must be"); + + destination = nativeCallTrampolineStub_at(destination)->destination(); return destination; } -void NativeCall::set_destination(address dest) { +void NativeFarCall::set_destination(address dest) { + assert(NativeFarCall::is_at((address)this), "unexpected code at call site"); assert(is_load_pc_relative_at(instruction_address()), "Must be"); - MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)dest); -} - -// Similar to replace_mt_safe, but just changes the destination. The -// important thing is that free-running threads are able to execute this -// call instruction at all times. -// -// Used in the runtime linkage of calls; see class CompiledIC. -// -// Add parameter assert_lock to switch off assertion -// during code generation, where no patching lock is needed. -void NativeCall::set_destination_mt_safe(address dest, bool assert_lock) { + assert(false, "Fix me"); +// MacroAssembler::pd_patch_instruction_size(instruction_address(), (address)dest); +} + +void NativeFarCall::verify() { + assert(NativeFarCall::is_at((address)this), "unexpected code at call site"); +} + +void NativeFarCall::print() { + assert(NativeFarCall::is_at((address)this), "unexpected code at call site"); + tty->print_cr(PTR_FORMAT ": jal/auipc,ld,jalr x1, offset/reg, ", p2i(instruction_address())); +} + +void NativeFarCall::set_destination_mt_safe(address dest, bool assert_lock) { + assert(NativeFarCall::is_at((address)this), "unexpected code at call site"); assert(!assert_lock || (Patching_lock->is_locked() || SafepointSynchronize::is_at_safepoint()) || CompiledICLocker::is_safe(addr_at(0)), "concurrent code patching"); address addr_call = addr_at(0); - assert(NativeCall::is_call_at(addr_call), "unexpected code at call site"); + assert(NativeFarCall::is_at(addr_call), "unexpected code at call site"); // Patch the constant in the call's trampoline stub. address trampoline_stub_addr = get_trampoline(); - if (trampoline_stub_addr != nullptr) { - assert (!is_NativeCallTrampolineStub_at(dest), "chained trampolines"); - nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); - } - - // Patch the call. - if (Assembler::reachable_from_branch_at(addr_call, dest)) { - set_destination(dest); - } else { - assert (trampoline_stub_addr != nullptr, "we need a trampoline"); - set_destination(trampoline_stub_addr); - } + assert(trampoline_stub_addr != nullptr, "Must be"); + assert (!is_NativeCallTrampolineStub_at(dest), "chained trampolines"); + nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest); ICache::invalidate_range(addr_call, instruction_size); } -address NativeCall::get_trampoline() { +address NativeFarCall::get_trampoline() { address call_addr = addr_at(0); CodeBlob *code = CodeCache::find_blob(call_addr); assert(code != nullptr, "Could not find the containing code blob"); + + assert(false, "Fix me"); + /* address jal_destination = MacroAssembler::pd_call_destination(call_addr); - if (code != nullptr && code->contains(jal_destination) && is_NativeCallTrampolineStub_at(jal_destination)) { + if (code != nullptr && code->contains(jal_destination) && is_NativeFarCallTrampolineStub_at(jal_destination)) { return jal_destination; } if (code != nullptr && code->is_nmethod()) { return trampoline_stub_Relocation::get_trampoline_for(call_addr, (nmethod*)code); } - +*/ return nullptr; } -// Inserts a native call instruction at a given pc -void NativeCall::insert(address code_pos, address entry) { Unimplemented(); } +NativeFarCall* NativeFarCall::at(address addr) { + assert_cond(addr != nullptr); + assert(NativeFarCall::is_at(addr), "unexpected code at call site"); + NativeFarCall* call = (NativeFarCall*)(addr); + return call; +} + +bool NativeFarCall::is_at(address addr) { + assert_cond(addr != nullptr); + const int instr_size = NativeInstruction::instruction_size; + if (NativeInstruction::is_auipc_at(addr) && + NativeInstruction::is_ld_at(addr + instr_size) && + NativeInstruction::is_jalr_at(addr + 2 * instr_size) && + (NativeInstruction::extract_rd(addr) == x5) && + (NativeInstruction::extract_rd(addr + instr_size) == x5) && + (NativeInstruction::extract_rs1(addr + instr_size) == x5) && + (NativeInstruction::extract_rs1(addr + 2 * instr_size) == x5) && + (NativeInstruction::extract_rd(addr + 2 * instr_size) == x1)) { + return true; + } + return false; +} + +bool NativeFarCall::is_call_before(address return_address) { + return false; +} + +void NativeFarCall::insert(address code_pos, address entry) { + Unimplemented(); +} + +void NativeFarCall::replace_mt_safe(address instr_addr, address code_buffer) { +} + + +//----------------------------------------------------------------------------- +// NativeCall + +address NativeCall::instruction_address() const { + if (NativeShortCall::is_at(address(this))) { + return NativeShortCall::at(address(this))->instruction_address(); + } + return 0; +} + +address NativeCall::next_instruction_address() const { + return 0; +} + +address NativeCall::return_address() const { + return 0; +} + +address NativeCall::destination() const { + return 0; +} + +void NativeCall::set_destination(address dest) { +} + +void NativeCall::verify() { +} + +void NativeCall::print() { + tty->print_cr(PTR_FORMAT ": jal/auipc,ld,jalr x1, offset/reg", p2i(instruction_address())); +} + +void NativeCall::set_destination_mt_safe(address dest, bool assert_lock = true) { +} + +address NativeCall::get_trampoline() { + return 0; +} + +bool NativeCall::is_call_before(address return_address) { + return false; +} + +void NativeCall::insert(address code_pos, address entry) { +} + +void NativeCall::replace_mt_safe(address instr_addr, address code_buffer) { +} //------------------------------------------------------------------- diff --git a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp index 58f0ecd27c3a9..e823d2516f8b8 100644 --- a/src/hotspot/cpu/riscv/nativeInst_riscv.hpp +++ b/src/hotspot/cpu/riscv/nativeInst_riscv.hpp @@ -210,23 +210,8 @@ class NativeInstruction { static bool is_li64_at(address instr); static bool is_pc_relative_at(address branch); static bool is_load_pc_relative_at(address branch); - - static bool is_call_at(address addr) { - assert_cond(addr != nullptr); - const int instr_size = NativeInstruction::instruction_size; - if (NativeInstruction::is_auipc_at(addr) && - NativeInstruction::is_ld_at(addr + instr_size) && - NativeInstruction::is_jalr_at(addr + 2 * instr_size) && - (NativeInstruction::extract_rd(addr) == x5) && - (NativeInstruction::extract_rd(addr + instr_size) == x5) && - (NativeInstruction::extract_rs1(addr + instr_size) == x5) && - (NativeInstruction::extract_rs1(addr + 2 * instr_size) == x5)) { - return true; - } - return false; - } + static bool is_call_at(address addr); static bool is_lwu_to_zr(address instr); - inline bool is_nop() const; inline bool is_jump_or_nop(); bool is_safepoint_poll(); @@ -234,20 +219,17 @@ class NativeInstruction { bool is_stop(); protected: - address addr_at(int offset) const { return address(this) + offset; } + address addr_at(int offset) const { return address(this) + offset; } + jint int_at(int offset) const { return (jint) Bytes::get_native_u4(addr_at(offset)); } + juint uint_at(int offset) const { return Bytes::get_native_u4(addr_at(offset)); } + address ptr_at(int offset) const { return (address) Bytes::get_native_u8(addr_at(offset)); } + oop oop_at(int offset) const { return cast_to_oop(Bytes::get_native_u8(addr_at(offset))); } - jint int_at(int offset) const { return (jint)Bytes::get_native_u4(addr_at(offset)); } - juint uint_at(int offset) const { return Bytes::get_native_u4(addr_at(offset)); } - address ptr_at(int offset) const { return (address)Bytes::get_native_u8(addr_at(offset)); } - - oop oop_at (int offset) const { return cast_to_oop(Bytes::get_native_u8(addr_at(offset))); } - - - void set_int_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } - void set_uint_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } - void set_ptr_at (int offset, address ptr) { Bytes::put_native_u8(addr_at(offset), (u8)ptr); } - void set_oop_at (int offset, oop o) { Bytes::put_native_u8(addr_at(offset), cast_from_oop(o)); } + void set_int_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } + void set_uint_at(int offset, jint i) { Bytes::put_native_u4(addr_at(offset), i); } + void set_ptr_at(int offset, address ptr) { Bytes::put_native_u8(addr_at(offset), (u8)ptr); } + void set_oop_at(int offset, oop o) { Bytes::put_native_u8(addr_at(offset), cast_from_oop(o)); } public: @@ -262,26 +244,53 @@ class NativeInstruction { } }; -inline NativeInstruction* nativeInstruction_at(address addr) { +NativeInstruction* nativeInstruction_at(address addr) { return (NativeInstruction*)addr; } // The natural type of an RISCV instruction is uint32_t -inline NativeInstruction* nativeInstruction_at(uint32_t *addr) { +NativeInstruction* nativeInstruction_at(uint32_t *addr) { return (NativeInstruction*)addr; } -inline NativeCall* nativeCall_at(address addr); -// The NativeCall is an abstraction for accessing/manipulating native -// call instructions (used to manipulate inline caches, primitive & -// DSO calls, etc.). +NativeCall* nativeCall_at(address addr); +NativeCall* nativeCall_before(address return_address); -class NativeCall: public NativeInstruction { +class NativeShortCall: public NativeInstruction { public: + // Creation + inline friend NativeCall* nativeCall_at(address addr); + inline friend NativeCall* nativeCall_before(address return_address); + + address instruction_address() const { return addr_at(0); } + address next_instruction_address() const { return addr_at(NativeInstruction::instruction_size); } + address return_address() const { return addr_at(NativeInstruction::instruction_size); } + address destination() const; + + void set_destination(address dest); + void verify_alignment() {} // do nothing on riscv + void verify(); + void print(); + + void set_destination_mt_safe(address dest, bool assert_lock = true); + + static NativeShortCall* at(address addr); + static bool is_at(address addr); + static bool is_call_before(address return_address); + static void insert(address code_pos, address entry); + static void replace_mt_safe(address instr_addr, address code_buffer); +}; + +class NativeFarCall: public NativeInstruction { + public: + // Creation + inline friend NativeCall* nativeCall_at(address addr); + inline friend NativeCall* nativeCall_before(address return_address); + enum RISCV_specific_constants { - instruction_size = 3 * NativeInstruction::instruction_size, + instruction_size = 3 * NativeInstruction::instruction_size, // ld auipc jalr instruction_offset = 0, - return_address_offset = 3 * NativeInstruction::instruction_size, + return_address_offset = 3 * NativeInstruction::instruction_size, // ld auipc jalr }; address instruction_address() const { return addr_at(instruction_offset); } @@ -293,48 +302,55 @@ class NativeCall: public NativeInstruction { void verify_alignment() {} // do nothing on riscv void verify(); void print(); + + void set_destination_mt_safe(address dest, bool assert_lock = true); + + address get_trampoline(); - // Creation - inline friend NativeCall* nativeCall_at(address addr); - inline friend NativeCall* nativeCall_before(address return_address); - - static bool is_call_before(address return_address) { - return is_call_at(return_address - NativeCall::return_address_offset); - } - - // MT-safe patching of a call instruction. + static NativeFarCall* at(address addr); + static bool is_at(address addr); + static bool is_call_before(address return_address); static void insert(address code_pos, address entry); - static void replace_mt_safe(address instr_addr, address code_buffer); +}; - // Similar to replace_mt_safe, but just changes the destination. The - // important thing is that free-running threads are able to execute - // this call instruction at all times. If the call is an immediate BL - // instruction we can simply rely on atomicity of 32-bit writes to - // make sure other threads will see no intermediate states. +// The NativeCall is an abstraction for accessing/manipulating native +// call instructions (used to manipulate inline caches, primitive & +// DSO calls, etc.). +class NativeCall: public NativeInstruction { + public: + // Creation + inline friend NativeCall* nativeCall_at(address addr); + inline friend NativeCall* nativeCall_before(address return_address); + + address instruction_address() const; + address next_instruction_address() const; + address return_address() const; + address destination() const; - // We cannot rely on locks here, since the free-running threads must run at - // full speed. - // - // Used in the runtime linkage of calls; see class CompiledIC. - // (Cf. 4506997 and 4479829, where threads witnessed garbage displacements.) + void set_destination(address dest); + void verify_alignment() {} // do nothing on riscv + void verify(); + void print(); - // The parameter assert_lock disables the assertion during code generation. void set_destination_mt_safe(address dest, bool assert_lock = true); - address get_trampoline(); + + static bool is_call_before(address return_address); + static void insert(address code_pos, address entry); + static void replace_mt_safe(address instr_addr, address code_buffer); }; inline NativeCall* nativeCall_at(address addr) { assert_cond(addr != nullptr); - NativeCall* call = (NativeCall*)(addr - NativeCall::instruction_offset); + NativeCall* call = (NativeCall*)(addr); DEBUG_ONLY(call->verify()); return call; } inline NativeCall* nativeCall_before(address return_address) { assert_cond(return_address != nullptr); - NativeCall* call = (NativeCall*)(return_address - NativeCall::return_address_offset); + NativeCall* call = (NativeCall*)(NativeInstruction::instruction_size); DEBUG_ONLY(call->verify()); return call; }