8337753: Target class of upcall stub may be unloaded

Reviewed-by: amitkumar, vlivanov, mdoerr
This commit is contained in:
Jorn Vernee 2024-10-03 12:02:24 +00:00
parent 19642bd383
commit 6af13580c2
23 changed files with 307 additions and 78 deletions

View File

@ -7320,6 +7320,28 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
// load Method* target of MethodHandle
// j_rarg0 = jobject receiver
// rmethod = result
address generate_upcall_stub_load_target() {
StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
__ resolve_global_jobject(j_rarg0, rscratch1, rscratch2);
// Load target method from receiver
__ load_heap_oop(rmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1, rscratch2);
__ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1, rscratch2);
__ load_heap_oop(rmethod, Address(rmethod, java_lang_invoke_MemberName::method_offset()), rscratch1, rscratch2);
__ access_load_at(T_ADDRESS, IN_HEAP, rmethod,
Address(rmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
noreg, noreg);
__ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
__ ret(lr);
return start;
}
#undef __
#define __ masm->
@ -8241,6 +8263,7 @@ class StubGenerator: public StubCodeGenerator {
#endif
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
StubRoutines::aarch64::set_completed(); // Inidicate that arraycopy and zero_blocks stubs are generated
}

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16;
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@ -222,7 +223,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ lea(c_rarg0, Address(sp, frame_data_offset));
__ movptr(c_rarg1, (intptr_t)receiver);
__ movptr(rscratch1, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry));
__ blr(rscratch1);
__ mov(rthread, r0);
@ -238,12 +238,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
__ get_vm_result(j_rarg0, rthread);
__ block_comment("} receiver ");
__ mov_metadata(rmethod, entry);
__ str(rmethod, Address(rthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
__ block_comment("{ load target ");
__ movptr(j_rarg0, (intptr_t)receiver);
__ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target()), rscratch1); // puts target Method* in rmethod
__ block_comment("} load target ");
__ push_cont_fastpath(rthread);
@ -318,7 +316,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
ss.print("upcall_stub_%s", entry->signature()->as_C_string());
ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";

View File

@ -25,7 +25,7 @@
#include "prims/upcallLinker.hpp"
#include "utilities/debug.hpp"
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,

View File

@ -4587,6 +4587,30 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
return start;
}
// load Method* target of MethodHandle
// R3_ARG1 = jobject receiver
// R19_method = result Method*
address generate_upcall_stub_load_target() {
StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
__ resolve_global_jobject(R3_ARG1, R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS);
// Load target method from receiver
__ load_heap_oop(R19_method, java_lang_invoke_MethodHandle::form_offset(), R3_ARG1,
R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
__ load_heap_oop(R19_method, java_lang_invoke_LambdaForm::vmentry_offset(), R19_method,
R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
__ load_heap_oop(R19_method, java_lang_invoke_MemberName::method_offset(), R19_method,
R22_tmp2, R23_tmp3, MacroAssembler::PRESERVATION_FRAME_LR_GP_FP_REGS, IS_NOT_NULL);
__ ld(R19_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset(), R19_method);
__ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread); // just in case callee is deoptimized
__ blr();
return start;
}
// Initialization
void generate_initial_stubs() {
// Generates all stubs and initializes the entry points
@ -4651,6 +4675,7 @@ address generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void generate_compiler_stubs() {

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@ -118,7 +119,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16; // arg save & restore + move
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@ -221,7 +222,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry), R0);
__ addi(R3_ARG1, R1_SP, frame_data_offset);
__ load_const_optimized(R4_ARG2, (intptr_t)receiver, R0);
__ call_c(call_target_address);
__ mr(R16_thread, R3_RET);
__ block_comment("} on_entry");
@ -236,12 +236,12 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(callerSP), frame::native_abi_minframe_size, frame::jit_out_preserve_size);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
__ get_vm_result(R3_ARG1);
__ block_comment("} receiver ");
__ load_const_optimized(R19_method, (intptr_t)entry);
__ std(R19_method, in_bytes(JavaThread::callee_target_offset()), R16_thread);
__ block_comment("{ load target ");
__ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target(), R0);
__ load_const_optimized(R3_ARG1, (intptr_t)receiver, R0);
__ mtctr(call_target_address);
__ bctrl(); // loads target Method* into R19_method
__ block_comment("} load target ");
__ push_cont_fastpath();
@ -326,7 +326,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
ss.print("upcall_stub_%s", entry->signature()->as_C_string());
ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";

View File

@ -6124,6 +6124,29 @@ static const int64_t right_3_bits = right_n_bits(3);
return start;
}
// load Method* target of MethodHandle
// j_rarg0 = jobject receiver
// xmethod = Method* result
address generate_upcall_stub_load_target() {
StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
__ resolve_global_jobject(j_rarg0, t0, t1);
// Load target method from receiver
__ load_heap_oop(xmethod, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), t0, t1);
__ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_LambdaForm::vmentry_offset()), t0, t1);
__ load_heap_oop(xmethod, Address(xmethod, java_lang_invoke_MemberName::method_offset()), t0, t1);
__ access_load_at(T_ADDRESS, IN_HEAP, xmethod,
Address(xmethod, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
noreg, noreg);
__ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
__ ret();
return start;
}
#undef __
// Initialization
@ -6189,6 +6212,7 @@ static const int64_t right_3_bits = right_n_bits(3);
#endif // COMPILER2
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
StubRoutines::riscv::set_completed();
}

View File

@ -25,6 +25,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@ -117,7 +118,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16;
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@ -223,7 +224,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ la(c_rarg0, Address(sp, frame_data_offset));
__ movptr(c_rarg1, (address) receiver);
__ rt_call(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry));
__ mv(xthread, x10);
__ reinit_heapbase();
@ -260,12 +260,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, as_VMStorage(shuffle_reg), abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
__ get_vm_result(j_rarg0, xthread);
__ block_comment("} receiver ");
__ mov_metadata(xmethod, entry);
__ sd(xmethod, Address(xthread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
__ block_comment("{ load target ");
__ movptr(j_rarg0, (address) receiver);
__ far_call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // loads Method* into xmethod
__ block_comment("} load target ");
__ push_cont_fastpath(xthread);
@ -338,7 +336,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
ss.print("upcall_stub_%s", entry->signature()->as_C_string());
ss.print("upcall_stub_%s", signature->as_C_string());
const char *name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";

View File

@ -3053,6 +3053,29 @@ class StubGenerator: public StubCodeGenerator {
return start;
}
// load Method* target of MethodHandle
// Z_ARG1 = jobject receiver
// Z_method = Method* result
address generate_upcall_stub_load_target() {
StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
__ resolve_global_jobject(Z_ARG1, Z_tmp_1, Z_tmp_2);
// Load target method from receiver
__ load_heap_oop(Z_method, Address(Z_ARG1, java_lang_invoke_MethodHandle::form_offset()),
noreg, noreg, IS_NOT_NULL);
__ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_LambdaForm::vmentry_offset()),
noreg, noreg, IS_NOT_NULL);
__ load_heap_oop(Z_method, Address(Z_method, java_lang_invoke_MemberName::method_offset()),
noreg, noreg, IS_NOT_NULL);
__ z_lg(Z_method, Address(Z_method, java_lang_invoke_ResolvedMethodName::vmtarget_offset()));
__ z_stg(Z_method, Address(Z_thread, JavaThread::callee_target_offset())); // just in case callee is deoptimized
__ z_br(Z_R14);
return start;
}
void generate_initial_stubs() {
// Generates all stubs and initializes the entry points.
@ -3110,6 +3133,7 @@ class StubGenerator: public StubCodeGenerator {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void generate_compiler_stubs() {

View File

@ -23,6 +23,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.inline.hpp"
#include "classfile/javaClasses.hpp"
#include "logging/logStream.hpp"
#include "memory/resourceArea.hpp"
#include "prims/upcallLinker.hpp"
@ -116,7 +117,7 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_size_per_arg = 16; // arg save & restore + move
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@ -206,7 +207,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("on_entry {");
__ load_const_optimized(call_target_address, CAST_FROM_FN_PTR(uint64_t, UpcallLinker::on_entry));
__ z_aghik(Z_ARG1, Z_SP, frame_data_offset);
__ load_const_optimized(Z_ARG2, (intptr_t)receiver);
__ call(call_target_address);
__ z_lgr(Z_thread, Z_RET);
__ block_comment("} on_entry");
@ -216,12 +216,11 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, frame::z_jit_out_preserve_size);
__ block_comment("} argument_shuffle");
__ block_comment("receiver {");
__ get_vm_result(Z_ARG1);
__ block_comment("} receiver");
__ load_const_optimized(Z_method, (intptr_t)entry);
__ z_stg(Z_method, Address(Z_thread, in_bytes(JavaThread::callee_target_offset())));
__ block_comment("load_target {");
__ load_const_optimized(Z_ARG1, (intptr_t)receiver);
__ load_const_optimized(call_target_address, StubRoutines::upcall_stub_load_target());
__ call(call_target_address); // load taget Method* into Z_method
__ block_comment("} load_target");
__ z_lg(call_target_address, Address(Z_method, in_bytes(Method::from_compiled_offset())));
__ call(call_target_address);
@ -274,7 +273,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
ss.print("upcall_stub_%s", entry->signature()->as_C_string());
ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.as_string());
#else // PRODUCT
const char* name = "upcall_stub";

View File

@ -24,6 +24,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/vmIntrinsics.hpp"
#include "compiler/oopMap.hpp"
#include "gc/shared/barrierSet.hpp"
@ -3796,6 +3797,28 @@ address StubGenerator::generate_upcall_stub_exception_handler() {
return start;
}
// load Method* target of MethodHandle
// j_rarg0 = jobject receiver
// rbx = result
address StubGenerator::generate_upcall_stub_load_target() {
StubCodeMark mark(this, "StubRoutines", "upcall_stub_load_target");
address start = __ pc();
__ resolve_global_jobject(j_rarg0, r15_thread, rscratch1);
// Load target method from receiver
__ load_heap_oop(rbx, Address(j_rarg0, java_lang_invoke_MethodHandle::form_offset()), rscratch1);
__ load_heap_oop(rbx, Address(rbx, java_lang_invoke_LambdaForm::vmentry_offset()), rscratch1);
__ load_heap_oop(rbx, Address(rbx, java_lang_invoke_MemberName::method_offset()), rscratch1);
__ access_load_at(T_ADDRESS, IN_HEAP, rbx,
Address(rbx, java_lang_invoke_ResolvedMethodName::vmtarget_offset()),
noreg, noreg);
__ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized
__ ret(0);
return start;
}
address StubGenerator::generate_lookup_secondary_supers_table_stub(u1 super_klass_index) {
StubCodeMark mark(this, "StubRoutines", "lookup_secondary_supers_table");
@ -3955,6 +3978,7 @@ void StubGenerator::generate_final_stubs() {
}
StubRoutines::_upcall_stub_exception_handler = generate_upcall_stub_exception_handler();
StubRoutines::_upcall_stub_load_target = generate_upcall_stub_load_target();
}
void StubGenerator::generate_compiler_stubs() {

View File

@ -620,6 +620,7 @@ class StubGenerator: public StubCodeGenerator {
// shared exception handler for FFM upcall stubs
address generate_upcall_stub_exception_handler();
address generate_upcall_stub_load_target();
// Specialized stub implementations for UseSecondarySupersTable.
address generate_lookup_secondary_supers_table_stub(u1 super_klass_index);

View File

@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "prims/upcallLinker.hpp"
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,

View File

@ -23,7 +23,7 @@
#include "precompiled.hpp"
#include "asm/macroAssembler.hpp"
#include "code/codeBlob.hpp"
#include "classfile/javaClasses.hpp"
#include "code/codeBlob.hpp"
#include "code/vmreg.inline.hpp"
#include "compiler/disassembler.hpp"
@ -169,10 +169,10 @@ static void restore_callee_saved_registers(MacroAssembler* _masm, const ABIDescr
__ block_comment("} restore_callee_saved_regs ");
}
static const int upcall_stub_code_base_size = 1024;
static const int upcall_stub_code_base_size = 1200;
static const int upcall_stub_size_per_arg = 16;
address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
address UpcallLinker::make_upcall_stub(jobject receiver, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,
@ -281,7 +281,6 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
__ block_comment("{ on_entry");
__ vzeroupper();
__ lea(c_rarg0, Address(rsp, frame_data_offset));
__ movptr(c_rarg1, (intptr_t)receiver);
// stack already aligned
__ call(RuntimeAddress(CAST_FROM_FN_PTR(address, UpcallLinker::on_entry)));
__ movptr(r15_thread, rax);
@ -297,12 +296,10 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
arg_shuffle.generate(_masm, shuffle_reg, abi._shadow_space_bytes, 0);
__ block_comment("} argument shuffle");
__ block_comment("{ receiver ");
__ get_vm_result(j_rarg0, r15_thread);
__ block_comment("} receiver ");
__ mov_metadata(rbx, entry);
__ movptr(Address(r15_thread, JavaThread::callee_target_offset()), rbx); // just in case callee is deoptimized
__ block_comment("{ load target ");
__ movptr(j_rarg0, (intptr_t)receiver);
__ call(RuntimeAddress(StubRoutines::upcall_stub_load_target())); // puts target Method* in rbx
__ block_comment("} load target ");
__ push_cont_fastpath();
@ -377,7 +374,7 @@ address UpcallLinker::make_upcall_stub(jobject receiver, Method* entry,
#ifndef PRODUCT
stringStream ss;
ss.print("upcall_stub_%s", entry->signature()->as_C_string());
ss.print("upcall_stub_%s", signature->as_C_string());
const char* name = _masm->code_string(ss.freeze());
#else // PRODUCT
const char* name = "upcall_stub";

View File

@ -24,7 +24,7 @@
#include "precompiled.hpp"
#include "prims/upcallLinker.hpp"
address UpcallLinker::make_upcall_stub(jobject mh, Method* entry,
address UpcallLinker::make_upcall_stub(jobject mh, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,

View File

@ -41,7 +41,7 @@
#include "runtime/handles.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaFrameAnchor.hpp"
#include "runtime/jniHandles.hpp"
#include "runtime/jniHandles.inline.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/safepoint.hpp"
#include "runtime/sharedRuntime.hpp"
@ -623,7 +623,7 @@ UpcallStub* UpcallStub::create(const char* name, CodeBuffer* cb, jobject receive
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
trace_new_stub(blob, "UpcallStub");
trace_new_stub(blob, "UpcallStub - ", name);
return blob;
}
@ -772,6 +772,10 @@ void UpcallStub::verify() {
void UpcallStub::print_on(outputStream* st) const {
RuntimeBlob::print_on(st);
print_value_on(st);
st->print_cr("Frame data offset: %d", (int) _frame_data_offset);
oop recv = JNIHandles::resolve(_receiver);
st->print("Receiver MH=");
recv->print_on(st);
Disassembler::decode((RuntimeBlob*)this, st);
}

View File

@ -22,7 +22,7 @@
*/
#include "precompiled.hpp"
#include "classfile/javaClasses.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/systemDictionary.hpp"
#include "compiler/compilationPolicy.hpp"
@ -73,7 +73,7 @@ JavaThread* UpcallLinker::maybe_attach_and_get_thread() {
}
// modelled after JavaCallWrapper::JavaCallWrapper
JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject receiver) {
JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context) {
JavaThread* thread = maybe_attach_and_get_thread();
guarantee(thread->thread_state() == _thread_in_native, "wrong thread state for upcall");
context->thread = thread;
@ -108,8 +108,6 @@ JavaThread* UpcallLinker::on_entry(UpcallStub::FrameData* context, jobject recei
debug_only(thread->inc_java_call_counter());
thread->set_active_handles(context->new_handles); // install new handle block and reset Java frame linkage
thread->set_vm_result(JNIHandles::resolve(receiver));
return thread;
}
@ -138,11 +136,10 @@ void UpcallLinker::on_exit(UpcallStub::FrameData* context) {
}
void UpcallLinker::handle_uncaught_exception(oop exception) {
ResourceMark rm;
// Based on CATCH macro
tty->print_cr("Uncaught exception:");
exception->print();
ShouldNotReachHere();
Handle exception_h(Thread::current(), exception);
java_lang_Throwable::print_stack_trace(exception_h, tty);
fatal("Unrecoverable uncaught exception encountered");
}
JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobject abi, jobject conv,
@ -150,36 +147,30 @@ JVM_ENTRY(jlong, UL_MakeUpcallStub(JNIEnv *env, jclass unused, jobject mh, jobje
ResourceMark rm(THREAD);
Handle mh_h(THREAD, JNIHandles::resolve(mh));
jobject mh_j = JNIHandles::make_global(mh_h);
oop type = java_lang_invoke_MethodHandle::type(mh_h());
oop lform = java_lang_invoke_MethodHandle::form(mh_h());
oop vmentry = java_lang_invoke_LambdaForm::vmentry(lform);
Method* entry = java_lang_invoke_MemberName::vmtarget(vmentry);
const methodHandle mh_entry(THREAD, entry);
assert(entry->method_holder()->is_initialized(), "no clinit barrier");
CompilationPolicy::compile_if_required(mh_entry, CHECK_0);
assert(entry->is_static(), "static only");
// Fill in the signature array, for the calling-convention call.
const int total_out_args = entry->size_of_parameters();
assert(total_out_args > 0, "receiver arg");
const int total_out_args = java_lang_invoke_MethodType::ptype_slot_count(type) + 1; // +1 for receiver
bool create_new = true;
TempNewSymbol signature = java_lang_invoke_MethodType::as_signature(type, create_new);
BasicType* out_sig_bt = NEW_RESOURCE_ARRAY(BasicType, total_out_args);
BasicType ret_type;
{
int i = 0;
SignatureStream ss(entry->signature());
out_sig_bt[i++] = T_OBJECT; // receiver MH
SignatureStream ss(signature);
for (; !ss.at_return_type(); ss.next()) {
out_sig_bt[i++] = ss.type(); // Collect remaining bits of signature
if (ss.type() == T_LONG || ss.type() == T_DOUBLE)
out_sig_bt[i++] = T_VOID; // Longs & doubles take 2 Java slots
}
assert(i == total_out_args, "");
assert(i == total_out_args, "%d != %d", i, total_out_args);
ret_type = ss.type();
}
return (jlong) UpcallLinker::make_upcall_stub(
mh_j, entry, out_sig_bt, total_out_args, ret_type,
mh_j, signature, out_sig_bt, total_out_args, ret_type,
abi, conv, needs_return_buffer, checked_cast<int>(ret_buf_size));
JVM_END

View File

@ -34,10 +34,10 @@ class UpcallLinker {
private:
static JavaThread* maybe_attach_and_get_thread();
static JavaThread* on_entry(UpcallStub::FrameData* context, jobject receiver);
static JavaThread* on_entry(UpcallStub::FrameData* context);
static void on_exit(UpcallStub::FrameData* context);
public:
static address make_upcall_stub(jobject mh, Method* entry,
static address make_upcall_stub(jobject mh, Symbol* signature,
BasicType* out_sig_bt, int total_out_args,
BasicType ret_type,
jobject jabi, jobject jconv,

View File

@ -719,6 +719,8 @@ void frame::print_on_error(outputStream* st, char* buf, int buflen, bool verbose
st->print("v ~MethodHandlesAdapterBlob " PTR_FORMAT, p2i(pc()));
} else if (_cb->is_uncommon_trap_stub()) {
st->print("v ~UncommonTrapBlob " PTR_FORMAT, p2i(pc()));
} else if (_cb->is_upcall_stub()) {
st->print("v ~UpcallStub::%s " PTR_FORMAT, _cb->name(), p2i(pc()));
} else {
st->print("v blob " PTR_FORMAT, p2i(pc()));
}
@ -1116,6 +1118,19 @@ void frame::oops_entry_do(OopClosure* f, const RegisterMap* map) const {
entry_frame_call_wrapper()->oops_do(f);
}
void frame::oops_upcall_do(OopClosure* f, const RegisterMap* map) const {
assert(map != nullptr, "map must be set");
if (map->include_argument_oops()) {
// Upcall stubs call a MethodHandle impl method of which only the receiver
// is ever an oop.
// Currently we should not be able to get here, since there are no
// safepoints in the one resolve stub we can get into (handle_wrong_method)
// Leave this here as a trap in case we ever do:
ShouldNotReachHere(); // not implemented
}
_cb->as_upcall_stub()->oops_do(f, *this);
}
bool frame::is_deoptimized_frame() const {
assert(_deopt_state != unknown, "not answerable");
if (_deopt_state == is_deoptimized) {
@ -1147,7 +1162,7 @@ void frame::oops_do_internal(OopClosure* f, NMethodClosure* cf,
} else if (is_entry_frame()) {
oops_entry_do(f, map);
} else if (is_upcall_stub_frame()) {
_cb->as_upcall_stub()->oops_do(f, *this);
oops_upcall_do(f, map);
} else if (CodeCache::contains(pc())) {
oops_nmethod_do(f, cf, df, derived_mode, map);
} else {

View File

@ -464,6 +464,7 @@ class frame {
const RegisterMap* map, bool use_interpreter_oop_map_cache) const;
void oops_entry_do(OopClosure* f, const RegisterMap* map) const;
void oops_upcall_do(OopClosure* f, const RegisterMap* map) const;
void oops_nmethod_do(OopClosure* f, NMethodClosure* cf,
DerivedOopClosure* df, DerivedPointerIterationMode derived_mode,
const RegisterMap* map) const;

View File

@ -188,6 +188,7 @@ address StubRoutines::_cont_returnBarrier = nullptr;
address StubRoutines::_cont_returnBarrierExc = nullptr;
address StubRoutines::_upcall_stub_exception_handler = nullptr;
address StubRoutines::_upcall_stub_load_target = nullptr;
address StubRoutines::_lookup_secondary_supers_table_slow_path_stub = nullptr;
address StubRoutines::_lookup_secondary_supers_table_stubs[Klass::SECONDARY_SUPERS_TABLE_SIZE] = { nullptr };

View File

@ -298,6 +298,7 @@ class StubRoutines: AllStatic {
static address _vector_d_math[VectorSupport::NUM_VEC_SIZES][VectorSupport::NUM_SVML_OP];
static address _upcall_stub_exception_handler;
static address _upcall_stub_load_target;
static address _lookup_secondary_supers_table_stubs[];
static address _lookup_secondary_supers_table_slow_path_stub;
@ -506,6 +507,11 @@ class StubRoutines: AllStatic {
return _upcall_stub_exception_handler;
}
static address upcall_stub_load_target() {
assert(_upcall_stub_load_target != nullptr, "not implemented");
return _upcall_stub_load_target;
}
static address lookup_secondary_supers_table_stub(u1 slot) {
assert(slot < Klass::SECONDARY_SUPERS_TABLE_SIZE, "out of bounds");
assert(_lookup_secondary_supers_table_stubs[slot] != nullptr, "not implemented");

View File

@ -381,7 +381,8 @@ jdk_svc = \
jdk_foreign = \
java/foreign \
jdk/internal/reflect/CallerSensitive/CheckCSMs.java \
-java/foreign/TestMatrix.java
-java/foreign/TestMatrix.java \
-java/foreign/TestUpcallStress.java
jdk_vector = \
jdk/incubator/vector

View File

@ -0,0 +1,97 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @requires jdk.foreign.linker != "FALLBACK"
* @requires (os.arch == "aarch64" | os.arch=="riscv64") & os.name == "Linux"
* @requires os.maxMemory > 4G
* @modules java.base/jdk.internal.foreign
* @build NativeTestHelper CallGeneratorHelper TestUpcallBase
* @bug 8337753
*
* @run testng/othervm/timeout=3200
* -Xcheck:jni
* -XX:+IgnoreUnrecognizedVMOptions
* -XX:-VerifyDependencies
* --enable-native-access=ALL-UNNAMED
* -Dgenerator.sample.factor=17
* TestUpcallStress
*/
import java.lang.foreign.Arena;
import java.lang.foreign.FunctionDescriptor;
import java.lang.foreign.MemorySegment;
import org.testng.annotations.Test;
import java.lang.invoke.MethodHandle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.*;
import java.util.function.Consumer;
public class TestUpcallStress extends TestUpcallBase {
static {
System.loadLibrary("TestUpcall");
}
@Test(dataProvider="functions", dataProviderClass=CallGeneratorHelper.class)
public void testUpcallsStress(int count, String fName, Ret ret, List<ParamType> paramTypes,
List<StructFieldType> fields) throws Throwable {
ExecutorService executor = Executors.newFixedThreadPool(16);
for (int threadIdx = 0; threadIdx < 16; threadIdx++) {
executor.submit(() -> {
for (int iter = 0; iter < 10000; iter++) {
List<Consumer<Object>> returnChecks = new ArrayList<>();
List<Consumer<Object>> argChecks = new ArrayList<>();
MemorySegment addr = findNativeOrThrow(fName);
try (Arena arena = Arena.ofConfined()) {
FunctionDescriptor descriptor = function(ret, paramTypes, fields);
MethodHandle mh = downcallHandle(LINKER, addr, arena, descriptor);
AtomicReference<Object[]> capturedArgs = new AtomicReference<>();
Object[] args = makeArgs(capturedArgs, arena, descriptor, returnChecks, argChecks, 0);
Object res = mh.invokeWithArguments(args);
if (ret == Ret.NON_VOID) {
returnChecks.forEach(c -> c.accept(res));
}
Object[] capturedArgsArr = capturedArgs.get();
for (int i = 0; i < capturedArgsArr.length; i++) {
argChecks.get(i).accept(capturedArgsArr[i]);
}
} catch (Throwable ex) {
throw new AssertionError(ex);
}
}
});
}
// This shutdownNow is 'wrong', since it doesn't wait for tasks to terminate,
// but it seems to be the only way to reproduce the race of JDK-8337753
executor.shutdownNow();
}
}