8286446: PPC64: fix crashes after JDK-8284161 (virtual threads preview)

Reviewed-by: mdoerr, coleenp, shade
This commit is contained in:
Richard Reingruber 2022-05-11 13:21:43 +00:00
parent 7a2bbbbce5
commit 87f3d2b870
8 changed files with 210 additions and 56 deletions

@ -229,20 +229,39 @@ address* frame::compiled_sender_pc_addr(CodeBlob* cb) const {
void frame::patch_pc(Thread* thread, address pc) {
assert(_cb == CodeCache::find_blob(pc), "unexpected pc");
address* pc_addr = (address*)&(own_abi()->lr);
if (TracePcPatching) {
tty->print_cr("patch_pc at address " PTR_FORMAT " [" PTR_FORMAT " -> " PTR_FORMAT "]",
p2i(&((address*) _sp)[-1]), p2i(((address*) _sp)[-1]), p2i(pc));
}
assert(!Continuation::is_return_barrier_entry(*pc_addr), "return barrier");
assert(_pc == *pc_addr || pc == *pc_addr || 0 == *pc_addr,
"must be (pc: " INTPTR_FORMAT " _pc: " INTPTR_FORMAT " pc_addr: " INTPTR_FORMAT
" *pc_addr: " INTPTR_FORMAT " sp: " INTPTR_FORMAT ")",
p2i(pc), p2i(_pc), p2i(pc_addr), p2i(*pc_addr), p2i(sp()));
DEBUG_ONLY(address old_pc = _pc;)
own_abi()->lr = (uint64_t)pc;
if (_cb != NULL && _cb->is_nmethod() && ((nmethod*)_cb)->is_deopt_pc(_pc)) {
address orig = (((nmethod*)_cb)->get_original_pc(this));
assert(orig == _pc, "expected original to be stored before patching");
_pc = pc; // must be set before call to get_deopt_original_pc
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
assert(original_pc == old_pc, "expected original PC to be stored before patching");
_deopt_state = is_deoptimized;
// Leave _pc as is.
_pc = original_pc;
} else {
_deopt_state = not_deoptimized;
_pc = pc;
}
assert(!is_compiled_frame() || !_cb->as_compiled_method()->is_deopt_entry(_pc), "must be");
#ifdef ASSERT
{
frame f(this->sp(), pc, this->unextended_sp());
assert(f.is_deoptimized_frame() == this->is_deoptimized_frame() && f.pc() == this->pc() && f.raw_pc() == this->raw_pc(),
"must be (f.is_deoptimized_frame(): %d this->is_deoptimized_frame(): %d "
"f.pc(): " INTPTR_FORMAT " this->pc(): " INTPTR_FORMAT " f.raw_pc(): " INTPTR_FORMAT " this->raw_pc(): " INTPTR_FORMAT ")",
f.is_deoptimized_frame(), this->is_deoptimized_frame(), p2i(f.pc()), p2i(this->pc()), p2i(f.raw_pc()), p2i(this->raw_pc()));
}
#endif
}
bool frame::is_interpreted_frame_valid(JavaThread* thread) const {
@ -384,9 +403,14 @@ intptr_t *frame::initial_deoptimization_info() {
#ifndef PRODUCT
// This is a generic constructor which is only used by pns() in debug.cpp.
frame::frame(void* sp, void* fp, void* pc) : _sp((intptr_t*)sp),
_pc((address)pc),
_cb(NULL),
_oop_map(NULL),
_on_heap(false),
_unextended_sp((intptr_t*)sp) {
find_codeblob_and_set_pc_and_deopt_state((address)pc); // also sets _fp and adjusts _unextended_sp
DEBUG_ONLY(_frame_index(-1) COMMA)
_unextended_sp((intptr_t*)sp),
_fp(NULL) {
setup(); // also sets _fp and adjusts _unextended_sp
}
#endif

@ -374,8 +374,8 @@
private:
// Find codeblob and set deopt_state.
inline void find_codeblob_and_set_pc_and_deopt_state(address pc);
// Initialize frame members (_pc and _sp must be given)
inline void setup();
public:
@ -383,7 +383,7 @@
// Constructors
inline frame(intptr_t* sp, address pc);
inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp);
inline frame(intptr_t* sp, address pc, intptr_t* unextended_sp, intptr_t* fp = nullptr, CodeBlob* cb = nullptr);
private:

@ -28,61 +28,66 @@
#include "code/codeCache.hpp"
#include "code/vmreg.inline.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/align.hpp"
// Inline functions for ppc64 frames:
// Find codeblob and set deopt_state.
inline void frame::find_codeblob_and_set_pc_and_deopt_state(address pc) {
assert(pc != NULL, "precondition: must have PC");
// Initialize frame members (_pc and _sp must be given)
inline void frame::setup() {
assert(_pc != nullptr, "precondition: must have PC");
_cb = CodeCache::find_blob(pc);
_pc = pc; // Must be set for get_deopt_original_pc()
_fp = (intptr_t*)own_abi()->callers_sp;
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != NULL) {
_pc = original_pc;
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
if (_cb == nullptr) {
_cb = CodeCache::find_blob(_pc);
}
assert(((uint64_t)_sp & 0xf) == 0, "SP must be 16-byte aligned");
if (_fp == nullptr) {
_fp = (intptr_t*)own_abi()->callers_sp;
}
// When thawing continuation frames the _unextended_sp passed to the constructor is not aligend
assert(_on_heap || (is_aligned(_sp, alignment_in_bytes) && is_aligned(_fp, alignment_in_bytes)),
"invalid alignment sp:" PTR_FORMAT " unextended_sp:" PTR_FORMAT " fp:" PTR_FORMAT, p2i(_sp), p2i(_unextended_sp), p2i(_fp));
address original_pc = CompiledMethod::get_deopt_original_pc(this);
if (original_pc != nullptr) {
_pc = original_pc;
_deopt_state = is_deoptimized;
assert(_cb == nullptr || _cb->as_compiled_method()->insts_contains_inclusive(_pc),
"original PC must be in the main code section of the the compiled method (or must be immediately following it)");
} else {
if (_cb == SharedRuntime::deopt_blob()) {
_deopt_state = is_deoptimized;
} else {
_deopt_state = not_deoptimized;
}
}
assert(_on_heap || is_aligned(_sp, frame::frame_alignment), "SP must be 16-byte aligned");
}
// Constructors
// Initialize all fields, _unextended_sp will be adjusted in find_codeblob_and_set_pc_and_deopt_state.
inline frame::frame() : _sp(NULL), _pc(NULL), _cb(NULL), _deopt_state(unknown), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(NULL), _fp(NULL) {}
inline frame::frame() : _sp(nullptr), _pc(nullptr), _cb(nullptr), _oop_map(nullptr), _deopt_state(unknown),
_on_heap(false), DEBUG_ONLY(_frame_index(-1) COMMA) _unextended_sp(nullptr), _fp(nullptr) {}
inline frame::frame(intptr_t* sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state((address)own_abi()->lr); // also sets _fp and adjusts _unextended_sp
inline frame::frame(intptr_t* sp)
: _sp(sp), _pc((address)own_abi()->lr), _cb(nullptr), _oop_map(nullptr),
_on_heap(false), DEBUG_ONLY(_frame_index(-1) COMMA) _unextended_sp(sp), _fp(nullptr) {
setup();
}
inline frame::frame(intptr_t* sp, address pc) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // also sets _fp and adjusts _unextended_sp
inline frame::frame(intptr_t* sp, address pc)
: _sp(sp), _pc(pc), _cb(nullptr), _oop_map(nullptr),
_on_heap(false), DEBUG_ONLY(_frame_index(-1) COMMA) _unextended_sp(sp), _fp(nullptr) {
setup();
}
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp) : _sp(sp), _on_heap(false),
#ifdef ASSERT
_frame_index(-1),
#endif
_unextended_sp(unextended_sp) {
find_codeblob_and_set_pc_and_deopt_state(pc); // also sets _fp and adjusts _unextended_sp
inline frame::frame(intptr_t* sp, address pc, intptr_t* unextended_sp, intptr_t* fp, CodeBlob* cb)
: _sp(sp), _pc(pc), _cb(nullptr), _oop_map(nullptr),
_on_heap(false), DEBUG_ONLY(_frame_index(-1) COMMA) _unextended_sp(unextended_sp), _fp(fp) {
setup();
}
// Accessors
@ -233,7 +238,16 @@ inline void frame::set_saved_oop_result(RegisterMap* map, oop obj) {
}
inline const ImmutableOopMap* frame::get_oop_map() const {
Unimplemented();
if (_cb == NULL) return NULL;
if (_cb->oop_maps() != NULL) {
NativePostCallNop* nop = nativePostCallNop_at(_pc);
if (nop != NULL && nop->displacement() != 0) {
int slot = ((nop->displacement() >> 24) & 0xff);
return _cb->oop_map_for_slot(slot, _pc);
}
const ImmutableOopMap* oop_map = OopMapSet::find_map(this);
return oop_map;
}
return NULL;
}

@ -506,13 +506,13 @@ class NativeMovRegMem: public NativeInstruction {
class NativePostCallNop: public NativeInstruction {
public:
bool check() const { Unimplemented(); return false; }
int displacement() const { Unimplemented(); return 0; }
int displacement() const { return 0; }
void patch(jint diff) { Unimplemented(); }
void make_deopt() { Unimplemented(); }
};
inline NativePostCallNop* nativePostCallNop_at(address address) {
Unimplemented();
// Unimplemented();
return NULL;
}
@ -524,7 +524,7 @@ public:
void verify() { Unimplemented(); }
static bool is_deopt_at(address instr) {
Unimplemented();
// Unimplemented();
return false;
}

@ -4501,6 +4501,87 @@ class StubGenerator: public StubCodeGenerator {
#endif // VM_LITTLE_ENDIAN
RuntimeStub* generate_cont_doYield() {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return nullptr;
}
address generate_cont_thaw(bool return_barrier, bool exception) {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return nullptr;
}
address generate_cont_thaw() {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return nullptr;
}
address generate_cont_returnBarrier() {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return nullptr;
}
address generate_cont_returnBarrier_exception() {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return nullptr;
}
#if INCLUDE_JFR
// For c2: c_rarg0 is junk, call to runtime to write a checkpoint.
// It returns a jobject handle to the event writer.
// The handle is dereferenced and the return value is the event writer oop.
RuntimeStub* generate_jfr_write_checkpoint() {
Register tmp1 = R10_ARG8;
Register tmp2 = R9_ARG7;
int insts_size = 512;
int locs_size = 64;
CodeBuffer code("jfr_write_checkpoint", insts_size, locs_size);
OopMapSet* oop_maps = new OopMapSet();
MacroAssembler* masm = new MacroAssembler(&code);
MacroAssembler* _masm = masm;
int framesize = frame::abi_reg_args_size / VMRegImpl::stack_slot_size;
address start = __ pc();
__ mflr(tmp1);
__ std(tmp1, _abi0(lr), R1_SP); // save return pc
__ push_frame_reg_args(0, tmp1);
int frame_complete = __ pc() - start;
__ set_last_Java_frame(R1_SP, noreg);
__ call_VM_leaf(CAST_FROM_FN_PTR(address, JfrIntrinsicSupport::write_checkpoint), R16_thread);
address calls_return_pc = __ last_calls_return_pc();
__ reset_last_Java_frame();
// The handle is dereferenced through a load barrier.
Label null_jobject;
__ cmpdi(CCR0, R3_RET, 0);
__ beq(CCR0, null_jobject);
DecoratorSet decorators = ACCESS_READ | IN_NATIVE;
BarrierSetAssembler* bs = BarrierSet::barrier_set()->barrier_set_assembler();
bs->load_at(_masm, decorators, T_OBJECT, R3_RET /*base*/, (intptr_t)0, R3_RET /*dst*/, tmp1, tmp2, MacroAssembler::PRESERVATION_NONE);
__ bind(null_jobject);
__ pop_frame();
__ ld(tmp1, _abi0(lr), R1_SP);
__ mtlr(tmp1);
__ blr();
OopMap* map = new OopMap(framesize, 0);
oop_maps->add_gc_map(calls_return_pc - start, map);
RuntimeStub* stub = // codeBlob framesize is in words (not VMRegImpl::slot_size)
RuntimeStub::new_runtime_stub("jfr_write_checkpoint", &code, frame_complete,
(framesize >> (LogBytesPerWord - LogBytesPerInt)),
oop_maps, false);
return stub;
}
#endif // INCLUDE_JFR
// Initialization
void generate_initial() {
// Generates all stubs and initializes the entry points
@ -4536,6 +4617,19 @@ class StubGenerator: public StubCodeGenerator {
}
}
void generate_phase1() {
// Continuation stubs:
StubRoutines::_cont_thaw = generate_cont_thaw();
StubRoutines::_cont_returnBarrier = generate_cont_returnBarrier();
StubRoutines::_cont_returnBarrierExc = generate_cont_returnBarrier_exception();
StubRoutines::_cont_doYield_stub = generate_cont_doYield();
StubRoutines::_cont_doYield = StubRoutines::_cont_doYield_stub == nullptr ? nullptr
: StubRoutines::_cont_doYield_stub->entry_point();
JFR_ONLY(StubRoutines::_jfr_write_checkpoint_stub = generate_jfr_write_checkpoint();)
JFR_ONLY(StubRoutines::_jfr_write_checkpoint = StubRoutines::_jfr_write_checkpoint_stub->entry_point();)
}
void generate_all() {
// Generates all stubs and initializes the entry points
@ -4608,11 +4702,13 @@ class StubGenerator: public StubCodeGenerator {
}
public:
StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
if (all) {
generate_all();
} else {
StubGenerator(CodeBuffer* code, int phase) : StubCodeGenerator(code) {
if (phase == 0) {
generate_initial();
} else if (phase == 1) {
generate_phase1(); // stubs that must be available for the interpreter
} else {
generate_all();
}
}
};

@ -477,6 +477,7 @@ address TemplateInterpreterGenerator::generate_abstract_entry(void) {
}
address TemplateInterpreterGenerator::generate_Continuation_doYield_entry(void) {
if (!Continuations::enabled()) return nullptr;
Unimplemented();
return NULL;
}

@ -104,6 +104,7 @@ bool Continuation::is_continuation_scope_mounted(JavaThread* thread, oop cont_sc
// The continuation object can be extracted from the thread.
bool Continuation::is_cont_barrier_frame(const frame& f) {
assert(f.is_interpreted_frame() || f.cb() != nullptr, "");
if (!Continuations::enabled()) return false;
return is_return_barrier_entry(f.is_interpreted_frame() ? ContinuationHelper::InterpretedFrame::return_pc(f)
: ContinuationHelper::CompiledFrame::return_pc(f));
}

@ -230,6 +230,14 @@ void Fingerprinter::do_type_calling_convention(BasicType type) {
case T_BYTE:
case T_SHORT:
case T_INT:
#if defined(PPC64)
if (_int_args < Argument::n_int_register_parameters_j) {
_int_args++;
} else {
_stack_arg_slots += 1;
}
break;
#endif // defined(PPC64)
case T_LONG:
case T_OBJECT:
case T_ARRAY:
@ -237,14 +245,24 @@ void Fingerprinter::do_type_calling_convention(BasicType type) {
if (_int_args < Argument::n_int_register_parameters_j) {
_int_args++;
} else {
PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
_stack_arg_slots += 2;
}
break;
case T_FLOAT:
#if defined(PPC64)
if (_fp_args < Argument::n_float_register_parameters_j) {
_fp_args++;
} else {
_stack_arg_slots += 1;
}
break;
#endif // defined(PPC64)
case T_DOUBLE:
if (_fp_args < Argument::n_float_register_parameters_j) {
_fp_args++;
} else {
PPC64_ONLY(_stack_arg_slots = align_up(_stack_arg_slots, 2));
_stack_arg_slots += 2;
}
break;