8288949: serviceability/jvmti/vthread/ContStackDepthTest/ContStackDepthTest.java failing

Reviewed-by: dlong, eosterlund, rehn
This commit is contained in:
Ron Pressler 2022-07-06 20:53:13 +00:00
parent 55fa19b508
commit 9a0fa82424
10 changed files with 208 additions and 29 deletions

View File

@ -708,7 +708,7 @@ void MacroAssembler::emit_static_call_stub() {
isb();
mov_metadata(rmethod, (Metadata*)NULL);
// Jump to the entry point of the i2c stub.
// Jump to the entry point of the c2i stub.
movptr(rscratch1, 0);
br(rscratch1);
}

View File

@ -1015,22 +1015,65 @@ static void gen_continuation_enter(MacroAssembler* masm,
int& exception_offset,
OopMapSet*oop_maps,
int& frame_complete,
int& stack_slots) {
int& stack_slots,
int& interpreted_entry_offset,
int& compiled_entry_offset) {
//verify_oop_args(masm, method, sig_bt, regs);
Address resolve(SharedRuntime::get_resolve_static_call_stub(),
relocInfo::static_call_type);
Address resolve(SharedRuntime::get_resolve_static_call_stub(), relocInfo::static_call_type);
stack_slots = 2; // will be overwritten
address start = __ pc();
Label call_thaw, exit;
// i2i entry used at interp_only_mode only
interpreted_entry_offset = __ pc() - start;
{
#ifdef ASSERT
Label is_interp_only;
__ ldrw(rscratch1, Address(rthread, JavaThread::interp_only_mode_offset()));
__ cbnzw(rscratch1, is_interp_only);
__ stop("enterSpecial interpreter entry called when not in interp_only_mode");
__ bind(is_interp_only);
#endif
// Read interpreter arguments into registers (this is an ad-hoc i2c adapter)
__ ldr(c_rarg1, Address(esp, Interpreter::stackElementSize*2));
__ ldr(c_rarg2, Address(esp, Interpreter::stackElementSize*1));
__ ldr(c_rarg3, Address(esp, Interpreter::stackElementSize*0));
__ push_cont_fastpath(rthread);
__ enter();
stack_slots = 2; // will be adjusted in setup
OopMap* map = continuation_enter_setup(masm, stack_slots);
// The frame is complete here, but we only record it for the compiled entry, so the frame would appear unsafe,
// but that's okay because at the very worst we'll miss an async sample, but we're in interp_only_mode anyway.
fill_continuation_entry(masm);
__ cmp(c_rarg2, (u1)0);
__ br(Assembler::NE, call_thaw);
address mark = __ pc();
__ trampoline_call1(resolve, NULL, false);
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
__ b(exit);
CodeBuffer* cbuf = masm->code_section()->outer();
CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
}
// compiled entry
__ align(CodeEntryAlignment);
compiled_entry_offset = __ pc() - start;
__ enter();
stack_slots = 2; // will be adjusted in setup
OopMap* map = continuation_enter_setup(masm, stack_slots);
// Frame is now completed as far as size and linkage.
frame_complete =__ pc() - start;
frame_complete = __ pc() - start;
fill_continuation_entry(masm);
@ -1038,7 +1081,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
__ br(Assembler::NE, call_thaw);
address mark = __ pc();
__ trampoline_call1(resolve, NULL, false);
oop_maps->add_gc_map(__ pc() - start, map);
@ -1081,7 +1123,7 @@ static void gen_continuation_enter(MacroAssembler* masm,
}
CodeBuffer* cbuf = masm->code_section()->outer();
address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
CompiledStaticCall::emit_to_interp_stub(*cbuf, mark);
}
static void gen_special_dispatch(MacroAssembler* masm,
@ -1171,11 +1213,12 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
if (method->is_continuation_enter_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();
int vep_offset = ((intptr_t)__ pc()) - start;
int vep_offset = 0;
int exception_offset = 0;
int frame_complete = 0;
int stack_slots = 0;
OopMapSet* oop_maps = new OopMapSet();
int interpreted_entry_offset = -1;
gen_continuation_enter(masm,
method,
in_sig_bt,
@ -1183,7 +1226,9 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
exception_offset,
oop_maps,
frame_complete,
stack_slots);
stack_slots,
interpreted_entry_offset,
vep_offset);
__ flush();
nmethod* nm = nmethod::new_native_nmethod(method,
compile_id,
@ -1195,7 +1240,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
in_ByteSize(-1),
oop_maps,
exception_offset);
ContinuationEntry::set_enter_code(nm);
ContinuationEntry::set_enter_code(nm, interpreted_entry_offset);
return nm;
}

View File

@ -1276,7 +1276,9 @@ static void gen_continuation_enter(MacroAssembler* masm,
int& exception_offset,
OopMapSet* oop_maps,
int& frame_complete,
int& stack_slots) {
int& stack_slots,
int& interpreted_entry_offset,
int& compiled_entry_offset) {
// enterSpecial(Continuation c, boolean isContinue, boolean isVirtualThread)
int pos_cont_obj = 0;
@ -1298,8 +1300,68 @@ static void gen_continuation_enter(MacroAssembler* masm,
// Utility methods kill rax, make sure there are no collisions
assert_different_registers(rax, reg_cont_obj, reg_is_cont, reg_is_virtual);
AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
relocInfo::static_call_type);
address start = __ pc();
Label L_thaw, L_exit;
// i2i entry used at interp_only_mode only
interpreted_entry_offset = __ pc() - start;
{
#ifdef ASSERT
Label is_interp_only;
__ cmpb(Address(r15_thread, JavaThread::interp_only_mode_offset()), 0);
__ jcc(Assembler::notEqual, is_interp_only);
__ stop("enterSpecial interpreter entry called when not in interp_only_mode");
__ bind(is_interp_only);
#endif
__ pop(rax); // return address
// Read interpreter arguments into registers (this is an ad-hoc i2c adapter)
__ movptr(c_rarg1, Address(rsp, Interpreter::stackElementSize*2));
__ movl(c_rarg2, Address(rsp, Interpreter::stackElementSize*1));
__ movl(c_rarg3, Address(rsp, Interpreter::stackElementSize*0));
__ andptr(rsp, -16); // Ensure compiled code always sees stack at proper alignment
__ push(rax); // return address
__ push_cont_fastpath();
__ enter();
stack_slots = 2; // will be adjusted in setup
OopMap* map = continuation_enter_setup(masm, stack_slots);
// The frame is complete here, but we only record it for the compiled entry, so the frame would appear unsafe,
// but that's okay because at the very worst we'll miss an async sample, but we're in interp_only_mode anyway.
__ verify_oop(reg_cont_obj);
fill_continuation_entry(masm, reg_cont_obj, reg_is_virtual);
// If continuation, call to thaw. Otherwise, resolve the call and exit.
__ testptr(reg_is_cont, reg_is_cont);
__ jcc(Assembler::notZero, L_thaw);
// --- Resolve path
// Make sure the call is patchable
__ align(BytesPerWord, __ offset() + NativeCall::displacement_offset);
// Emit stub for static call
CodeBuffer* cbuf = masm->code_section()->outer();
address stub = CompiledStaticCall::emit_to_interp_stub(*cbuf, __ pc());
if (stub == nullptr) {
fatal("CodeCache is full at gen_continuation_enter");
}
__ call(resolve);
oop_maps->add_gc_map(__ pc() - start, map);
__ post_call_nop();
__ jmp(L_exit);
}
// compiled entry
__ align(CodeEntryAlignment);
compiled_entry_offset = __ pc() - start;
__ enter();
stack_slots = 2; // will be adjusted in setup
@ -1312,8 +1374,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
fill_continuation_entry(masm, reg_cont_obj, reg_is_virtual);
Label L_thaw, L_exit;
// If continuation, call to thaw. Otherwise, resolve the call and exit.
__ testptr(reg_is_cont, reg_is_cont);
__ jccb(Assembler::notZero, L_thaw);
@ -1330,9 +1390,6 @@ static void gen_continuation_enter(MacroAssembler* masm,
fatal("CodeCache is full at gen_continuation_enter");
}
// Call the resolve stub
AddressLiteral resolve(SharedRuntime::get_resolve_static_call_stub(),
relocInfo::static_call_type);
__ call(resolve);
oop_maps->add_gc_map(__ pc() - start, map);
@ -1471,17 +1528,20 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
if (method->is_continuation_enter_intrinsic()) {
vmIntrinsics::ID iid = method->intrinsic_id();
intptr_t start = (intptr_t)__ pc();
int vep_offset = ((intptr_t)__ pc()) - start;
int vep_offset = 0;
int exception_offset = 0;
int frame_complete = 0;
int stack_slots = 0;
OopMapSet* oop_maps = new OopMapSet();
int interpreted_entry_offset = -1;
gen_continuation_enter(masm,
in_regs,
exception_offset,
oop_maps,
frame_complete,
stack_slots);
stack_slots,
interpreted_entry_offset,
vep_offset);
__ flush();
nmethod* nm = nmethod::new_native_nmethod(method,
compile_id,
@ -1493,7 +1553,7 @@ nmethod* SharedRuntime::generate_native_wrapper(MacroAssembler* masm,
in_ByteSize(-1),
oop_maps,
exception_offset);
ContinuationEntry::set_enter_code(nm);
ContinuationEntry::set_enter_code(nm, interpreted_entry_offset);
return nm;
}

View File

@ -39,6 +39,7 @@
#include "oops/method.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "runtime/continuationEntry.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/safepoint.hpp"
@ -653,6 +654,13 @@ void CompiledStaticCall::compute_entry(const methodHandle& m, bool caller_is_nme
}
}
void CompiledStaticCall::compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info) {
if (ContinuationEntry::is_interpreted_call(instruction_address())) {
info._to_interpreter = true;
info._entry = m()->get_c2i_entry();
}
}
address CompiledDirectStaticCall::find_stub_for(address instruction) {
// Find reloc. information containing this call-site
RelocIterator iter((nmethod*)NULL, instruction);

View File

@ -345,6 +345,7 @@ class CompiledStaticCall : public ResourceObj {
// Compute entry point given a method
static void compute_entry(const methodHandle& m, bool caller_is_nmethod, StaticCallInfo& info);
void compute_entry_for_continuation_entry(const methodHandle& m, StaticCallInfo& info);
public:
// Clean static call (will force resolving on next use)

View File

@ -61,6 +61,7 @@
#include "prims/methodHandles.hpp"
#include "runtime/arguments.hpp"
#include "runtime/atomic.hpp"
#include "runtime/continuationEntry.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/init.hpp"
@ -1328,7 +1329,7 @@ void Method::set_code(const methodHandle& mh, CompiledMethod *code) {
assert(mh->_from_interpreted_entry == NULL, "initialized incorrectly"); // see link_method
// This is the entry used when we're in interpreter-only mode; see InterpreterMacroAssembler::jump_from_interpreted
mh->_i2i_entry = mh->get_i2c_entry();
mh->_i2i_entry = ContinuationEntry::interpreted_entry();
// This must come last, as it is what's tested in LinkResolver::resolve_static_call
Atomic::release_store(&mh->_from_interpreted_entry , mh->get_i2c_entry());
} else if (!mh->is_method_handle_intrinsic()) {

View File

@ -23,6 +23,7 @@
*/
#include "precompiled.hpp"
#include "code/compiledIC.hpp"
#include "code/nmethod.hpp"
#include "runtime/continuation.hpp"
#include "runtime/continuationEntry.inline.hpp"
@ -34,10 +35,32 @@
int ContinuationEntry::_return_pc_offset = 0;
address ContinuationEntry::_return_pc = nullptr;
CompiledMethod* ContinuationEntry::_enter_special = nullptr;
int ContinuationEntry::_interpreted_entry_offset = 0;
void ContinuationEntry::set_enter_code(CompiledMethod* cm) {
void ContinuationEntry::set_enter_code(CompiledMethod* cm, int interpreted_entry_offset) {
assert(_return_pc_offset != 0, "");
_return_pc = cm->code_begin() + _return_pc_offset;
_enter_special = cm;
_interpreted_entry_offset = interpreted_entry_offset;
assert(_enter_special->code_contains(compiled_entry()), "entry not in enterSpecial");
assert(_enter_special->code_contains(interpreted_entry()), "entry not in enterSpecial");
assert(interpreted_entry() < compiled_entry(), "unexpected code layout");
}
address ContinuationEntry::compiled_entry() {
return _enter_special->verified_entry_point();
}
address ContinuationEntry::interpreted_entry() {
return _enter_special->code_begin() + _interpreted_entry_offset;
}
bool ContinuationEntry::is_interpreted_call(address call_address) {
assert(_enter_special->code_contains(call_address), "call not in enterSpecial");
assert(call_address >= interpreted_entry(), "unexpected location");
return call_address < compiled_entry();
}
ContinuationEntry* ContinuationEntry::from_frame(const frame& f) {

View File

@ -52,10 +52,13 @@ public:
public:
static int _return_pc_offset; // friend gen_continuation_enter
static void set_enter_code(CompiledMethod* nm); // friend SharedRuntime::generate_native_wrapper
static void set_enter_code(CompiledMethod* cm, int interpreted_entry_offset);
static bool is_interpreted_call(address call_address);
private:
static address _return_pc;
static CompiledMethod* _enter_special;
static int _interpreted_entry_offset;
private:
ContinuationEntry* _parent;
@ -89,6 +92,11 @@ public:
intptr_t* entry_sp() const { return (intptr_t*)this; }
intptr_t* entry_fp() const;
static address compiled_entry();
static address interpreted_entry();
static CompiledMethod* enter_special() { return _enter_special; }
int argsize() const { return _argsize; }
void set_argsize(int value) { _argsize = value; }

View File

@ -1343,6 +1343,9 @@ bool SharedRuntime::resolve_sub_helper_internal(methodHandle callee_method, cons
return true; // skip patching for JVMCI
}
CompiledStaticCall* ssc = caller_nm->compiledStaticCall_before(caller_frame.pc());
if (is_nmethod && caller_nm->method()->is_continuation_enter_intrinsic()) {
ssc->compute_entry_for_continuation_entry(callee_method, static_call_info);
}
if (ssc->is_clean()) ssc->set(static_call_info);
}
}
@ -1557,10 +1560,32 @@ JRT_END
// resolve a static call and patch code
JRT_BLOCK_ENTRY(address, SharedRuntime::resolve_static_call_C(JavaThread* current ))
methodHandle callee_method;
bool enter_special = false;
JRT_BLOCK
callee_method = SharedRuntime::resolve_helper(false, false, CHECK_NULL);
current->set_vm_result_2(callee_method());
if (current->is_interp_only_mode()) {
RegisterMap reg_map(current, false);
frame stub_frame = current->last_frame();
assert(stub_frame.is_runtime_frame(), "must be a runtimeStub");
frame caller = stub_frame.sender(&reg_map);
enter_special = caller.cb() != NULL && caller.cb()->is_compiled()
&& caller.cb()->as_compiled_method()->method()->is_continuation_enter_intrinsic();
}
JRT_BLOCK_END
if (current->is_interp_only_mode() && enter_special) {
// enterSpecial is compiled and calls this method to resolve the call to Continuation::enter
// but in interp_only_mode we need to go to the interpreted entry
// The c2i won't patch in this mode -- see fixup_callers_callsite
//
// This should probably be done in all cases, not just enterSpecial (see JDK-8218403),
// but that's part of a larger fix, and the situation is worse for enterSpecial, as it has no
// interpreted version.
return callee_method->get_c2i_entry();
}
// return compiled code entry point after potential safepoints
assert(callee_method->verified_code_entry() != NULL, " Jump to zero!");
return callee_method->verified_code_entry();
@ -1991,6 +2016,9 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal
// Get the return PC for the passed caller PC.
address return_pc = caller_pc + frame::pc_return_offset;
assert(!JavaThread::current()->is_interp_only_mode() || !nm->method()->is_continuation_enter_intrinsic()
|| ContinuationEntry::is_interpreted_call(return_pc), "interp_only_mode but not in enterSpecial interpreted entry");
// There is a benign race here. We could be attempting to patch to a compiled
// entry point at the same time the callee is being deoptimized. If that is
// the case then entry_point may in fact point to a c2i and we'd patch the
@ -2027,6 +2055,13 @@ JRT_LEAF(void, SharedRuntime::fixup_callers_callsite(Method* method, address cal
typ != relocInfo::static_stub_type) {
return;
}
if (nm->method()->is_continuation_enter_intrinsic()) {
assert(ContinuationEntry::is_interpreted_call(call->instruction_address()) == JavaThread::current()->is_interp_only_mode(),
"mode: %d", JavaThread::current()->is_interp_only_mode());
if (ContinuationEntry::is_interpreted_call(call->instruction_address())) {
return;
}
}
address destination = call->destination();
if (should_fixup_call_destination(destination, entry_point, caller_pc, moop, cb)) {
call->set_destination_mt_safe(entry_point);
@ -3056,7 +3091,7 @@ void AdapterHandlerLibrary::create_native_wrapper(const methodHandle& method) {
CodeBuffer buffer(buf);
if (method->is_continuation_enter_intrinsic()) {
buffer.initialize_stubs_size(64);
buffer.initialize_stubs_size(128);
}
struct { double data[20]; } locs_buf;

View File

@ -36,5 +36,3 @@ serviceability/sa/TestJhsdbJstackMixed.java 8248675 linux-aarch64
vmTestbase/nsk/jvmti/scenarios/sampling/SP07/sp07t002/TestDescription.java 8245680 windows-x64
vmTestbase/vm/mlvm/mixed/stress/regression/b6969574/INDIFY_Test.java 8265295 linux-x64,windows-x64
serviceability/jvmti/vthread/ContStackDepthTest/ContStackDepthTest.java 8288949 generic-all