Skip to content

Commit

Permalink
Working
Browse files Browse the repository at this point in the history
  • Loading branch information
robehn committed Mar 21, 2024
1 parent cd35321 commit 8387994
Show file tree
Hide file tree
Showing 6 changed files with 136 additions and 110 deletions.
2 changes: 1 addition & 1 deletion src/hotspot/cpu/riscv/c1_LIRAssembler_riscv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ friend class ArrayCopyStub;
// See emit_static_call_stub for detail
// CompiledDirectCall::to_interp_stub_size() (14) + CompiledDirectCall::to_trampoline_stub_size() (1 + 3 + address)
_call_stub_size = 14 * NativeInstruction::instruction_size +
(NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size),
(NativeInstruction::instruction_size + NativeShortCallTrampolineStub::instruction_size),
// See emit_exception_handler for detail
// verify_not_null_oop + far_call + should_not_reach_here + invalidate_registers(DEBUG_ONLY)
_exception_handler_size = DEBUG_ONLY(584) NOT_DEBUG(548), // or smaller
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/riscv/codeBuffer_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ static bool emit_shared_trampolines(CodeBuffer* cb, CodeBuffer::SharedTrampoline
address stub = __ emit_trampoline_stub(offset, dest);
assert(stub, "pre-allocated trampolines");

address reloc_pc = cb->stubs()->end() - NativeCallTrampolineStub::instruction_size;
address reloc_pc = cb->stubs()->end() - NativeShortCallTrampolineStub::instruction_size;
while (!it.is_empty()) {
offset = *it.next();
address caller_pc = cb->insts()->start() + offset;
Expand Down
76 changes: 46 additions & 30 deletions src/hotspot/cpu/riscv/macroAssembler_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3547,8 +3547,11 @@ address MacroAssembler::trampoline_call(Address entry) {
}
#endif
relocate(entry.rspec(), [&] {
// load_link(target, t0);
jump_link(target, t0);
if (UseNewCode) {
load_link(target, t0);
} else {
jump_link(target, t0);
}
});

postcond(pc() != badAddress);
Expand Down Expand Up @@ -3605,7 +3608,19 @@ int MacroAssembler::ic_check(int end_alignment) {
return uep_offset;
}

address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset, address dest) {
// Emit a trampoline stub for a call to a target which is too far away.
//
// code sequences:
//
// call-site:
// branch-and-link to <destination> or <trampoline stub>
//
// Related trampoline stub for this call site in the stub section:
// load the call target from the constant pool
// branch (RA still points to the call site above)

address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset,
address dest) {
// Max stub size: alignment nop, TrampolineStub.
address stub = start_a_stub(max_trampoline_stub_size());
if (stub == nullptr) {
Expand All @@ -3620,49 +3635,50 @@ address MacroAssembler::emit_trampoline_stub(int insts_call_instruction_offset,
// instructions code-section.

// Make sure the address of destination 8-byte aligned after 3 instructions.
align(wordSize, NativeCallTrampolineStub::data_offset);
align(wordSize, NativeShortCallTrampolineStub::data_offset);

RelocationHolder rh = trampoline_stub_Relocation::spec(code()->insts()->start() +
insts_call_instruction_offset);
const int stub_start_offset = offset();
relocate(rh, [&] {
// Now, create the trampoline stub's code:
// - load the call
// - call
Label target;
ld(t0, target); // auipc + ld
jr(t0); // jalr
bind(target);
assert(offset() - stub_start_offset == NativeCallTrampolineStub::data_offset,
"should be");
assert(offset() % wordSize == 0, "bad alignment");
emit_int64((int64_t)dest);
});

/*
relocate(rh, [&] {
assert(offset() - stub_start_offset == NativeCallTrampolineStub::data_offset,
"%ld - %ld == %ld : should be", (long)offset(), (long)stub_start_offset, (long)NativeCallTrampolineStub::data_offset);
assert(offset() % wordSize == 0, "bad alignment");
printf("Trampo data: %p\n", pc());
emit_int64((int64_t)dest);
emit_int32((int32_t)0xabababababu);
emit_int32((int32_t)0xdcdcdcdcdcu);
if (UseNewCode) {
assert(offset() - stub_start_offset == NativeShortCallTrampolineStub::data_offset,
"%ld - %ld == %ld : should be", (long)offset(), (long)stub_start_offset, (long)NativeShortCallTrampolineStub::data_offset);
assert(offset() % wordSize == 0, "bad alignment");
printf("Trampo data: %p\n", pc());
emit_int64((int64_t)dest);
emit_int32((int32_t)0xabababababu);
emit_int32((int32_t)0xdcdcdcdcdcu);
} else {
// Now, create the trampoline stub's code:
// - load the call
// - call
Label target;
ld(t0, target); // auipc + ld
jr(t0); // jalr
bind(target);
assert(offset() - stub_start_offset == NativeShortCallTrampolineStub::data_offset,
"should be");
assert(offset() % wordSize == 0, "bad alignment");
emit_int64((int64_t)dest);
}
});
*/

const address stub_start_addr = addr_at(stub_start_offset);

assert(is_NativeCallTrampolineStub_at(stub_start_addr), "doesn't look like a trampoline");
assert(NativeShortCallTrampolineStub::is_at(stub_start_addr), "doesn't look like a trampoline");

end_a_stub();
return stub_start_addr;
}

int MacroAssembler::max_trampoline_stub_size() {
// Max stub size: alignment nop, TrampolineStub.
// return 2 * wordSize;
return NativeInstruction::instruction_size + NativeCallTrampolineStub::instruction_size;
if (UseNewCode) {
return 2 * wordSize;
} else {
return NativeInstruction::instruction_size + NativeShortCallTrampolineStub::instruction_size;
}
}

int MacroAssembler::static_call_stub_size() {
Expand Down
85 changes: 68 additions & 17 deletions src/hotspot/cpu/riscv/nativeInst_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,10 @@ address NativeShortCall::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)) {
if (nm != nullptr && nm->stub_contains(destination) && NativeShortCallTrampolineStub::is_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();
destination = NativeShortCallTrampolineStub::at(trampoline_stub_addr)->destination();
}

return destination;
Expand All @@ -163,6 +163,7 @@ void NativeShortCall::set_destination(address dest) {
set_int_at(0, insn);
}


void NativeShortCall::verify() {
assert(NativeShortCall::is_at((address)this), "unexpected code at call site");
}
Expand All @@ -184,8 +185,8 @@ void NativeShortCall::set_destination_mt_safe(address dest, bool assert_lock) {
// 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);
assert (!NativeShortCallTrampolineStub::is_at(dest), "chained trampolines");
NativeShortCallTrampolineStub::at(trampoline_stub_addr)->set_destination(dest);
}

// Patch the call.
Expand All @@ -206,7 +207,7 @@ address NativeShortCall::get_trampoline() {
assert(code != nullptr, "Could not find the containing code blob");

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) && NativeShortCallTrampolineStub::is_at(jal_destination)) {
return jal_destination;
}

Expand Down Expand Up @@ -246,6 +247,49 @@ void NativeShortCall::replace_mt_safe(address instr_addr, address code_buffer) {
Unimplemented();
}

//-----------------------------------------------------------------------------
// NativeShortCallTrampoline

address NativeShortCallTrampolineStub::destination(nmethod *nm) const {
return ptr_at(data_offset);
}

void NativeShortCallTrampolineStub::set_destination(address new_destination) {
set_ptr_at(data_offset, new_destination);
OrderAccess::release();
}

bool NativeShortCallTrampolineStub::is_at(address addr) {
// Ensure that the stub is exactly
// ld t0, L--->auipc + ld
// jr t0
// L:

// judge inst + register + imm
// 1). check the instructions: auipc + ld + jalr
// 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0
// 3). check if the offset in ld[31:20] equals the data_offset
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) &&
(Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == NativeShortCallTrampolineStub::data_offset)) {
return true;
}
return false;
}

NativeShortCallTrampolineStub* NativeShortCallTrampolineStub::at(address addr) {
assert_cond(addr != nullptr);
assert(NativeShortCallTrampolineStub::is_at(addr), "no call trampoline found");
return (NativeShortCallTrampolineStub*)addr;
}

//-----------------------------------------------------------------------------
// NativeFarCall

Expand All @@ -261,9 +305,9 @@ address NativeFarCall::destination() const {
assert(cb && cb->is_nmethod(), "sanity");
nmethod *nm = (nmethod *)cb;
assert(nm != nullptr && nm->stub_contains(destination), "No tramp");
assert(is_NativeCallTrampolineStub_at(destination), "Must be");
assert(NativeShortCallTrampolineStub::is_at(destination), "Must be");

destination = nativeCallTrampolineStub_at(destination)->destination();
destination = NativeShortCallTrampolineStub::at(destination)->destination();

return destination;
}
Expand Down Expand Up @@ -297,8 +341,8 @@ void NativeFarCall::set_destination_mt_safe(address dest, bool assert_lock) {
// Patch the constant in the call's trampoline stub.
address trampoline_stub_addr = get_trampoline();
assert(trampoline_stub_addr != nullptr, "Must be");
assert (!is_NativeCallTrampolineStub_at(dest), "chained trampolines");
nativeCallTrampolineStub_at(trampoline_stub_addr)->set_destination(dest);
assert (!NativeShortCallTrampolineStub::is_at(dest), "chained trampolines");
NativeShortCallTrampolineStub::at(trampoline_stub_addr)->set_destination(dest);
*/
ICache::invalidate_range(addr_call, instruction_size);
}
Expand All @@ -324,6 +368,21 @@ address NativeFarCall::get_trampoline() {
return nullptr;
}

/*
bool NativeFarCallTrampoline::is_NativeFarCallTrampolineStub_at(address addr) {
assert_cond(addr != nullptr);
const int instr_size = NativeInstruction::instruction_size;
uint32_t top = Assembler::ld_instr(addr);
uint32_t low = Assembler::ld_instr(addr + instr_size);
uint32_t magic = Assembler::ld_instr(addr + (2 * instr_size));
printf("===>> %x %x %x <<==\n", top, low, magic);
if (magic == 0xababababu) {
return true;
}
return false;
}
*/

NativeFarCall* NativeFarCall::at(address addr) {
assert_cond(addr != nullptr);
assert(NativeFarCall::is_at(addr), "unexpected code at call site");
Expand Down Expand Up @@ -658,14 +717,6 @@ void NativeGeneralJump::replace_mt_safe(address instr_addr, address code_buffer)
ShouldNotCallThis();
}

address NativeCallTrampolineStub::destination(nmethod *nm) const {
return ptr_at(data_offset);
}

void NativeCallTrampolineStub::set_destination(address new_destination) {
set_ptr_at(data_offset, new_destination);
OrderAccess::release();
}

uint32_t NativeMembar::get_kind() {
uint32_t insn = uint_at(0);
Expand Down
79 changes: 19 additions & 60 deletions src/hotspot/cpu/riscv/nativeInst_riscv.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,25 @@ class NativeShortCall: public NativeInstruction {
static void replace_mt_safe(address instr_addr, address code_buffer);
};

class NativeShortCallTrampolineStub : public NativeInstruction {
public:

enum RISCV_specific_constants {
// Refer to function emit_trampoline_stub.
instruction_size = 3 * NativeInstruction::instruction_size + wordSize, // auipc + ld + jr + target address
data_offset = 3 * NativeInstruction::instruction_size, // auipc + ld + jr
instruction_size2 = 2 * wordSize,
data_offset2 = 0 * wordSize
};

address destination(nmethod *nm = nullptr) const;
void set_destination(address new_destination);
ptrdiff_t destination_offset() const;

static bool is_at(address addr);
static NativeShortCallTrampolineStub* at(address addr);
};

class NativeFarCall: public NativeInstruction {
public:
// Creation
Expand Down Expand Up @@ -525,66 +544,6 @@ inline bool NativeInstruction::is_jump_or_nop() {
return is_nop() || is_jump();
}

// Call trampoline stubs.
class NativeCallTrampolineStub : public NativeInstruction {
public:

enum RISCV_specific_constants {
// Refer to function emit_trampoline_stub.
instruction_size = 3 * NativeInstruction::instruction_size + wordSize, // auipc + ld + jr + target address
data_offset = 3 * NativeInstruction::instruction_size, // auipc + ld + jr
instruction_size2 = 2 * wordSize,
data_offset2 = 0 * wordSize
};

address destination(nmethod *nm = nullptr) const;
void set_destination(address new_destination);
ptrdiff_t destination_offset() const;
};

inline bool is_NativeCallTrampolineStub_at(address addr) {
// Ensure that the stub is exactly
// ld t0, L--->auipc + ld
// jr t0
// L:

// judge inst + register + imm
// 1). check the instructions: auipc + ld + jalr
// 2). check if auipc[11:7] == t0 and ld[11:7] == t0 and ld[19:15] == t0 && jr[19:15] == t0
// 3). check if the offset in ld[31:20] equals the data_offset
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) &&
(Assembler::extract(Assembler::ld_instr(addr + 4), 31, 20) == NativeCallTrampolineStub::data_offset)) {
return true;
}
return false;
}

inline bool is_NativeCallTrampolineStub_at2(address addr) {
assert_cond(addr != nullptr);
const int instr_size = NativeInstruction::instruction_size;
uint32_t top = Assembler::ld_instr(addr);
uint32_t low = Assembler::ld_instr(addr + instr_size);
uint32_t magic = Assembler::ld_instr(addr + (2 * instr_size));
printf("===>> %x %x %x <<==\n", top, low, magic);
if (magic == 0xababababu) {
return true;
}
return false;
}

inline NativeCallTrampolineStub* nativeCallTrampolineStub_at(address addr) {
assert_cond(addr != nullptr);
assert(is_NativeCallTrampolineStub_at(addr), "no call trampoline found");
return (NativeCallTrampolineStub*)addr;
}

class NativeMembar : public NativeInstruction {
public:
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/cpu/riscv/relocInfo_riscv.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ address Relocation::pd_call_destination(address orig_addr) {
if (NativeCall::is_call_at(addr())) {
address trampoline = nativeCall_at(addr())->get_trampoline();
if (trampoline != nullptr) {
return nativeCallTrampolineStub_at(trampoline)->destination();
return NativeShortCallTrampolineStub::at(trampoline)->destination();
}
}
if (orig_addr != nullptr) {
Expand Down

0 comments on commit 8387994

Please sign in to comment.