Skip to content

Commit c5d8068

Browse files
committed
8286300: Port JEP 425 to S390X
8338383: Implement JEP 491: Synchronize Virtual Threads without Pinning 8369238: Allow virtual thread preemption on some common class initialization paths
1 parent ff2b7b3 commit c5d8068

37 files changed

Lines changed: 2199 additions & 307 deletions

src/hotspot/cpu/s390/abstractInterpreter_s390.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,8 @@ void AbstractInterpreter::layout_activation(Method* method,
197197
assert(is_bottom_frame && (sender_sp == caller->unextended_sp()),
198198
"must initialize sender_sp of bottom skeleton frame when pushing it");
199199
} else {
200-
assert(caller->is_entry_frame() || caller->is_upcall_stub_frame(), "is there a new frame type??");
200+
// FIXME: sender_sp correctly calculated for native frames ?
201+
assert(caller->is_entry_frame() || caller->is_upcall_stub_frame() || caller->is_native_frame(), "is there a new frame type??");
201202
sender_sp = caller->sp(); // Call_stub only uses it's fp.
202203
}
203204

src/hotspot/cpu/s390/assembler_s390.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3279,6 +3279,9 @@ class Assembler : public AbstractAssembler {
32793279
static bool is_z_nop(address x) {
32803280
return is_z_nop(* (short *) x);
32813281
}
3282+
static bool is_z_illtrap(address x) {
3283+
return *(uint16_t*)x == 0u;
3284+
}
32823285
static bool is_z_br(long x) {
32833286
return is_z_bcr(x) && ((x & 0x00f0) == 0x00f0);
32843287
}

src/hotspot/cpu/s390/c1_LIRAssembler_s390.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,7 @@ void LIR_Assembler::call(LIR_OpJavaCall* op, relocInfo::relocType rtype) {
524524
__ z_nop();
525525
__ z_brasl(Z_R14, op->addr());
526526
add_call_info(code_offset(), op->info());
527+
__ post_call_nop();
527528
}
528529

529530
void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
@@ -540,6 +541,7 @@ void LIR_Assembler::ic_call(LIR_OpJavaCall* op) {
540541
// to determine who we intended to call.
541542
__ relocate(virtual_call_Relocation::spec(virtual_call_oop_addr));
542543
call(op, relocInfo::none);
544+
__ post_call_nop();
543545
}
544546

545547
void LIR_Assembler::move_regs(Register from_reg, Register to_reg) {
@@ -2845,6 +2847,7 @@ void LIR_Assembler::rt_call(LIR_Opr result, address dest,
28452847
if (info != nullptr) {
28462848
add_call_info_here(info);
28472849
}
2850+
__ post_call_nop();
28482851
}
28492852

28502853
void LIR_Assembler::volatile_move_op(LIR_Opr src, LIR_Opr dest, BasicType type, CodeEmitInfo* info) {

src/hotspot/cpu/s390/c1_Runtime1_s390.cpp

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
5757
// z_abi_160.gpr14 (e.g. InterpreterRuntime::_new()).
5858
// Therefore we load the PC into Z_R1_scratch and let set_last_Java_frame() save
5959
// it into the frame anchor.
60-
address pc = get_PC(Z_R1_scratch);
61-
int call_offset = (int)(pc - addr_at(0));
60+
Label resume;
61+
z_larl(Z_R1_scratch, resume);
6262
set_last_Java_frame(Z_SP, Z_R1_scratch);
6363

6464
// ARG1 must hold thread address.
@@ -67,9 +67,12 @@ int StubAssembler::call_RT(Register oop_result1, Register metadata_result, addre
6767
address return_pc = nullptr;
6868
align_call_far_patchable(this->pc());
6969
return_pc = call_c_opt(entry_point);
70+
71+
bind(resume);
72+
int call_offset = offset(); // (int)(return_pc - addr_at(0));
7073
assert(return_pc != nullptr, "const section overflow");
7174

72-
reset_last_Java_frame();
75+
reset_last_Java_frame(/* check_last_java_sp= */ false);
7376

7477
// Check for pending exceptions.
7578
{
@@ -208,8 +211,37 @@ void Runtime1::initialize_pd() {
208211
}
209212

210213
uint Runtime1::runtime_blob_current_thread_offset(frame f) {
211-
Unimplemented();
212-
return 0;
214+
CodeBlob* cb = f.cb();
215+
assert(cb == Runtime1::blob_for(StubId::c1_monitorenter_id) ||
216+
cb == Runtime1::blob_for(StubId::c1_monitorenter_nofpu_id), "must be");
217+
assert(cb != nullptr && cb->is_runtime_stub(), "invalid frame");
218+
219+
// Calculate the offset of Z_thread (Z_R8) in the saved register area.
220+
// Both c1_monitorenter_id and c1_monitorenter_nofpu_id have the same frame layout:
221+
// - c1_monitorenter_id uses RegisterSaver::all_registers (saves FPU regs)
222+
// - c1_monitorenter_nofpu_id uses RegisterSaver::all_integer_registers (excludes FPU regs but reserves space)
223+
//
224+
// From RegisterSaver_LiveRegs and RegisterSaver_LiveIntRegs:
225+
// Both have 15 float register slots (F0, F2-F15, F1 is excluded as scratch)
226+
// Then integer registers: R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, R13
227+
// Z_thread is Z_R8, which is the 7th integer register (index 6 from R2)
228+
//
229+
// Stack layout from SP:
230+
// [0..159] : z_abi_160
231+
// [160..279] : 15 float register slots (15 * 8 = 120 bytes)
232+
// [280..327] : R2-R7 (6 * 8 = 48 bytes)
233+
// [328..335] : R8 (Z_thread) <- this is what we need
234+
//
235+
// Offset = 160 + 120 + 48 = 328 bytes from SP
236+
// Return value is in 64-bit words: 328 / 8 = 41
237+
238+
const int float_reg_slots = 15; // F0, F2-F15 (F1 is scratch, excluded)
239+
const int int_regs_before_r8 = 6; // R2, R3, R4, R5, R6, R7
240+
const int z_thread_offset = frame::z_abi_160_size +
241+
(float_reg_slots * 8) +
242+
(int_regs_before_r8 * 8);
243+
244+
return z_thread_offset / 8; // Convert to 64-bit words
213245
}
214246

215247
OopMapSet* Runtime1::generate_exception_throw(StubAssembler* sasm, address target, bool has_argument) {

src/hotspot/cpu/s390/continuationEntry_s390.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,11 @@
2525
#ifndef CPU_S390_CONTINUATIONENTRY_S390_HPP
2626
#define CPU_S390_CONTINUATIONENTRY_S390_HPP
2727

28+
#include "runtime/frame.hpp"
29+
2830
class ContinuationEntryPD {
29-
// empty
31+
// This is needed to position the ContinuationEntry at the unextended sp of the entry frame
32+
frame::z_abi_160_base _abi;
3033
};
3134

3235
#endif // CPU_S390_CONTINUATIONENTRY_S390_HPP

src/hotspot/cpu/s390/continuationEntry_s390.inline.hpp

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,22 +25,28 @@
2525
#ifndef CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP
2626
#define CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP
2727

28+
#include "oops/method.inline.hpp"
29+
#include "runtime/frame.inline.hpp"
30+
#include "runtime/registerMap.hpp"
31+
#include "utilities/macros.hpp"
2832
#include "runtime/continuationEntry.hpp"
2933

30-
// TODO: Implement
31-
3234
inline frame ContinuationEntry::to_frame() const {
33-
Unimplemented();
34-
return frame();
35+
static CodeBlob* cb = CodeCache::find_blob_fast(entry_pc());
36+
assert(cb != nullptr, "");
37+
assert(cb->as_nmethod()->method()->is_continuation_enter_intrinsic(), "");
38+
return frame(entry_sp(), entry_pc(), entry_sp(), entry_fp(), cb);
3539
}
3640

3741
inline intptr_t* ContinuationEntry::entry_fp() const {
38-
Unimplemented();
39-
return nullptr;
42+
return (intptr_t*)((address)this + size());
4043
}
4144

4245
inline void ContinuationEntry::update_register_map(RegisterMap* map) const {
43-
Unimplemented();
46+
// No register map update needed for s390.
47+
// In the Java calling convention on s390, all registers are volatile (caller-saved),
48+
// so there are no non-volatile (callee-saved) registers that need to be tracked
49+
// in the register map for continuation entry frames.
4450
}
4551

4652
#endif // CPU_S390_CONTINUATIONENTRY_S390_INLINE_HPP

0 commit comments

Comments
 (0)