From 6af13580c2086afefde489275bc2353c2320ff3f Mon Sep 17 00:00:00 2001 From: Jorn Vernee Date: Thu, 3 Oct 2024 12:02:24 +0000 Subject: [PATCH 001/113] 8337753: Target class of upcall stub may be unloaded Reviewed-by: amitkumar, vlivanov, mdoerr --- .../cpu/aarch64/stubGenerator_aarch64.cpp | 23 +++++ .../cpu/aarch64/upcallLinker_aarch64.cpp | 16 ++- src/hotspot/cpu/arm/upcallLinker_arm.cpp | 2 +- src/hotspot/cpu/ppc/stubGenerator_ppc.cpp | 25 +++++ src/hotspot/cpu/ppc/upcallLinker_ppc.cpp | 18 ++-- src/hotspot/cpu/riscv/stubGenerator_riscv.cpp | 24 +++++ src/hotspot/cpu/riscv/upcallLinker_riscv.cpp | 16 ++- src/hotspot/cpu/s390/stubGenerator_s390.cpp | 24 +++++ src/hotspot/cpu/s390/upcallLinker_s390.cpp | 17 ++-- src/hotspot/cpu/x86/stubGenerator_x86_64.cpp | 24 +++++ src/hotspot/cpu/x86/stubGenerator_x86_64.hpp | 1 + src/hotspot/cpu/x86/upcallLinker_x86_32.cpp | 2 +- src/hotspot/cpu/x86/upcallLinker_x86_64.cpp | 19 ++-- src/hotspot/cpu/zero/upcallLinker_zero.cpp | 2 +- src/hotspot/share/code/codeBlob.cpp | 8 +- src/hotspot/share/prims/upcallLinker.cpp | 35 +++---- src/hotspot/share/prims/upcallLinker.hpp | 4 +- src/hotspot/share/runtime/frame.cpp | 17 +++- src/hotspot/share/runtime/frame.hpp | 1 + src/hotspot/share/runtime/stubRoutines.cpp | 1 + src/hotspot/share/runtime/stubRoutines.hpp | 6 ++ test/jdk/TEST.groups | 3 +- test/jdk/java/foreign/TestUpcallStress.java | 97 +++++++++++++++++++ 23 files changed, 307 insertions(+), 78 deletions(-) create mode 100644 test/jdk/java/foreign/TestUpcallStress.java diff --git a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp index eb235f8472c..31116e006f0 100644 --- a/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/stubGenerator_aarch64.cpp @@ -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 } diff --git a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp index 28ec07815be..517fccb2d1a 100644 --- a/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/upcallLinker_aarch64.cpp @@ -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"; diff --git a/src/hotspot/cpu/arm/upcallLinker_arm.cpp b/src/hotspot/cpu/arm/upcallLinker_arm.cpp index c7645f4a033..696b2001e6b 100644 --- a/src/hotspot/cpu/arm/upcallLinker_arm.cpp +++ b/src/hotspot/cpu/arm/upcallLinker_arm.cpp @@ -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, diff --git a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp index ee3f1911e20..206c161287f 100644 --- a/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/stubGenerator_ppc.cpp @@ -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() { diff --git a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp index b60fd4f16d1..635bab900d1 100644 --- a/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp +++ b/src/hotspot/cpu/ppc/upcallLinker_ppc.cpp @@ -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"; diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 5970111088f..8bf3ac5c901 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -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(); } diff --git a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp index 383f332f8fd..55160be99d0 100644 --- a/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp +++ b/src/hotspot/cpu/riscv/upcallLinker_riscv.cpp @@ -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"; diff --git a/src/hotspot/cpu/s390/stubGenerator_s390.cpp b/src/hotspot/cpu/s390/stubGenerator_s390.cpp index d878731cca5..dd9ed4c9546 100644 --- a/src/hotspot/cpu/s390/stubGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/stubGenerator_s390.cpp @@ -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() { diff --git a/src/hotspot/cpu/s390/upcallLinker_s390.cpp b/src/hotspot/cpu/s390/upcallLinker_s390.cpp index 734b4e89c7c..8baad40a519 100644 --- a/src/hotspot/cpu/s390/upcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/upcallLinker_s390.cpp @@ -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"; diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 4f37dc31d03..835bfc770fe 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -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() { diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index 71777fbfffe..7280e9fbe95 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -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); diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp index e5075e180d9..d795c751d02 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_32.cpp @@ -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, diff --git a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp index 82179f9022e..bc261bfd93f 100644 --- a/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp +++ b/src/hotspot/cpu/x86/upcallLinker_x86_64.cpp @@ -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"; diff --git a/src/hotspot/cpu/zero/upcallLinker_zero.cpp b/src/hotspot/cpu/zero/upcallLinker_zero.cpp index 6447dac86c9..408ebc32820 100644 --- a/src/hotspot/cpu/zero/upcallLinker_zero.cpp +++ b/src/hotspot/cpu/zero/upcallLinker_zero.cpp @@ -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, diff --git a/src/hotspot/share/code/codeBlob.cpp b/src/hotspot/share/code/codeBlob.cpp index 81c4d001078..23f621ffec8 100644 --- a/src/hotspot/share/code/codeBlob.cpp +++ b/src/hotspot/share/code/codeBlob.cpp @@ -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); } diff --git a/src/hotspot/share/prims/upcallLinker.cpp b/src/hotspot/share/prims/upcallLinker.cpp index b02746911a8..1abce57652a 100644 --- a/src/hotspot/share/prims/upcallLinker.cpp +++ b/src/hotspot/share/prims/upcallLinker.cpp @@ -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(ret_buf_size)); JVM_END diff --git a/src/hotspot/share/prims/upcallLinker.hpp b/src/hotspot/share/prims/upcallLinker.hpp index d80516b2566..765ed63fc5a 100644 --- a/src/hotspot/share/prims/upcallLinker.hpp +++ b/src/hotspot/share/prims/upcallLinker.hpp @@ -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, diff --git a/src/hotspot/share/runtime/frame.cpp b/src/hotspot/share/runtime/frame.cpp index e193271eff6..17078a69ab9 100644 --- a/src/hotspot/share/runtime/frame.cpp +++ b/src/hotspot/share/runtime/frame.cpp @@ -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 { diff --git a/src/hotspot/share/runtime/frame.hpp b/src/hotspot/share/runtime/frame.hpp index 1c57e3de4da..50aafce3837 100644 --- a/src/hotspot/share/runtime/frame.hpp +++ b/src/hotspot/share/runtime/frame.hpp @@ -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; diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index a2b8c1da644..331aa3c7364 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -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 }; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index b58c591bbf7..be9577d542f 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -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"); diff --git a/test/jdk/TEST.groups b/test/jdk/TEST.groups index 0c6b13fdca0..d51fcec733b 100644 --- a/test/jdk/TEST.groups +++ b/test/jdk/TEST.groups @@ -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 diff --git a/test/jdk/java/foreign/TestUpcallStress.java b/test/jdk/java/foreign/TestUpcallStress.java new file mode 100644 index 00000000000..40607746856 --- /dev/null +++ b/test/jdk/java/foreign/TestUpcallStress.java @@ -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 paramTypes, + List 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> returnChecks = new ArrayList<>(); + List> 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 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(); + } +} From d7f32d891cde2278fe7158fb28d29235db5c818c Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 3 Oct 2024 12:08:23 +0000 Subject: [PATCH 002/113] 8341415: Optimize RawBytecodeHelper::next Reviewed-by: liach --- .../classfile/impl/RawBytecodeHelper.java | 57 +++++++++---------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java index 2403ae150e9..659f41f9699 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/RawBytecodeHelper.java @@ -299,7 +299,6 @@ public static int align(int n) { private int nextBci; private int bci; private int opcode; - private boolean isWide; public static CodeRange of(byte[] array) { return new CodeRange(array, array.length); @@ -341,14 +340,14 @@ public void reset(int nextBci) { * be valid and can be accessed unchecked. */ public int opcode() { - return opcode; + return opcode & 0xFF; } /** * Returns whether the current functional opcode is in wide. */ public boolean isWide() { - return isWide; + return (opcode & (WIDE << 8)) != 0; } /** @@ -411,7 +410,7 @@ public int destW() { // *load, *store, iinc public int getIndex() { - return isWide ? getU2Unchecked(bci + 2) : getIndexU1(); + return isWide() ? getU2Unchecked(bci + 2) : getIndexU1(); } // ldc @@ -443,12 +442,11 @@ public boolean next() { int len = LENGTHS[code & 0xFF]; // & 0xFF eliminates bound check this.bci = bci; opcode = code; - isWide = false; if (len <= 0) { len = checkSpecialInstruction(bci, end, code); // sets opcode } - if (len <= 0 || (nextBci += len) > end) { + if ((nextBci += len) > end) { opcode = ILLEGAL; } @@ -457,37 +455,34 @@ public boolean next() { // Put rarely used code in another method to reduce code size private int checkSpecialInstruction(int bci, int end, int code) { + int len = -1; if (code == WIDE) { - if (bci + 1 >= end) { - return -1; + if (bci + 1 < end) { + opcode = (WIDE << 8) | (code = getIndexU1()); + // Validated in UtilTest.testOpcodeLengthTable + len = LENGTHS[code] * 2; } - opcode = code = getIndexU1(); - isWide = true; - // Validated in UtilTest.testOpcodeLengthTable - return LENGTHS[code] * 2; - } - if (code == TABLESWITCH) { + } else if (code == TABLESWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 3 * 4 >= end) { - return -1; + if (alignedBci + 3 * 4 < end) { + int lo = getIntUnchecked(alignedBci + 1 * 4); + int hi = getIntUnchecked(alignedBci + 2 * 4); + long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; } - int lo = getIntUnchecked(alignedBci + 1 * 4); - int hi = getIntUnchecked(alignedBci + 2 * 4); - long l = alignedBci - bci + (3L + (long) hi - lo + 1L) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; - } - if (code == LOOKUPSWITCH) { + } else if (code == LOOKUPSWITCH) { int alignedBci = align(bci + 1); - if (alignedBci + 2 * 4 >= end) { - return -1; - } - int npairs = getIntUnchecked(alignedBci + 4); - if (npairs < 0) { - return -1; + if (alignedBci + 2 * 4 < end) { + int npairs = getIntUnchecked(alignedBci + 4); + if (npairs >= 0) { + long l = alignedBci - bci + (2L + 2L * npairs) * 4L; + len = l > 0 && ((int) l == l) ? (int) l : -1; + } } - long l = alignedBci - bci + (2L + 2L * npairs) * 4L; - return l > 0 && ((int) l == l) ? (int) l : -1; } - return -1; + if (len <= 0) { + opcode = ILLEGAL; + } + return len; } } From 7d524d7e378430afb3a262e8fe544bd1be22748c Mon Sep 17 00:00:00 2001 From: Abhishek Kumar Date: Thu, 3 Oct 2024 12:20:01 +0000 Subject: [PATCH 003/113] 8341004: Open source AWT FileDialog related tests Reviewed-by: kizune --- .../awt/FileDialog/DoubleActionCloseX.java | 75 +++++++++++ .../java/awt/FileDialog/DoubleActionESC.java | 122 ++++++++++++++++++ .../FileDialog/TestFileDialogDupJNIRef.java | 82 ++++++++++++ 3 files changed, 279 insertions(+) create mode 100644 test/jdk/java/awt/FileDialog/DoubleActionCloseX.java create mode 100644 test/jdk/java/awt/FileDialog/DoubleActionESC.java create mode 100644 test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java diff --git a/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java new file mode 100644 index 00000000000..5d3feaa42ed --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionCloseX.java @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2005, 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. + */ + +import java.awt.Button; +import java.awt.FileDialog; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 6227750 + * @summary Tests that FileDialog can be closed by clicking the 'close' (X) button + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DoubleActionCloseX + */ + +public class DoubleActionCloseX { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + NOTE: On Linux and Mac, there is no 'close'(X) button + when file dialog is visible, press Pass. + + Click the 'Open File Dialog' button to open FileDialog. + A file dialog will appear on the screen. + Click on the 'close'(X) button. + The dialog should be closed. + If not, the test failed, press Fail otherwise press Pass. + """; + + PassFailJFrame.builder() + .title("DoubleActionCloseX Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(DoubleActionCloseX::createUI) + .build() + .awaitAndCheck(); + } + public static Frame createUI() { + Frame f = new Frame("DoubleActionCloseX Test"); + Button b = new Button("Open File Dialog"); + FileDialog fd = new FileDialog(f); + b.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + fd.setVisible(true); + } + }); + f.add(b); + f.setSize(300, 200); + return f; + } +} diff --git a/test/jdk/java/awt/FileDialog/DoubleActionESC.java b/test/jdk/java/awt/FileDialog/DoubleActionESC.java new file mode 100644 index 00000000000..748c3aeb5e4 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/DoubleActionESC.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2005, 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. + */ + +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.util.concurrent.CountDownLatch; + +/* + * @test + * @bug 5097243 + * @summary Tests that FileDialog can be closed by ESC any time + * @key headful + * @run main DoubleActionESC + */ + +public class DoubleActionESC { + private static Frame f; + private static Button showBtn; + private static FileDialog fd; + private static Robot robot; + private static volatile Point p; + private static volatile Dimension d; + private static volatile CountDownLatch latch; + private static final int REPEAT_COUNT = 2; + + public static void main(String[] args) throws Exception { + latch = new CountDownLatch(1); + + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + + robot.delay(1000); + EventQueue.invokeAndWait(() -> { + p = showBtn.getLocationOnScreen(); + d = showBtn.getSize(); + }); + + for (int i = 0; i < REPEAT_COUNT; ++i) { + Thread thread = new Thread(() -> { + robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + }); + thread.start(); + robot.delay(3000); + + Thread thread1 = new Thread(() -> { + robot.keyPress(KeyEvent.VK_ESCAPE); + robot.keyRelease(KeyEvent.VK_ESCAPE); + robot.waitForIdle(); + }); + thread1.start(); + robot.delay(3000); + } + + latch.await(); + if (fd.isVisible()) { + throw new RuntimeException("File Dialog is not closed"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + public static void createAndShowUI() { + f = new Frame("DoubleActionESC Test"); + showBtn = new Button("Show File Dialog"); + fd = new FileDialog(f); + showBtn.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + if (e.getSource() == showBtn) { + fd.setSize(200, 200); + fd.setLocation(200, 200); + fd.setVisible(true); + latch.countDown(); + } + } + }); + f.add(showBtn); + f.setSize(300, 200); + f.setLocationRelativeTo(null); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java new file mode 100644 index 00000000000..56b6c492144 --- /dev/null +++ b/test/jdk/java/awt/FileDialog/TestFileDialogDupJNIRef.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2003, 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. + */ + +import java.awt.Button; +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.FlowLayout; +import java.awt.Frame; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4906972 + * @summary Tests using of JNI reference to peer object. + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual TestFileDialogDupJNIRef + */ + +public class TestFileDialogDupJNIRef { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + This is a crash test. + After test started you will see 'Test Frame' with one button. + 1. Click the button to open FileDialog. + 2. Go to the dialog and choose any directory with some files in it.. + 3. Click on any file to highlight it. + 4. Click on the file again to rename. + 5. Leave the file in edit mode and click Open button + + If there was no crash the test passed, Press Pass. + """; + + PassFailJFrame.builder() + .title("TestFileDialogDupJNIRef Instruction") + .instructions(INSTRUCTIONS) + .columns(40) + .testUI(TestFileDialogDupJNIRef::createUI) + .build() + .awaitAndCheck(); + } + + public static Frame createUI() { + Frame frame = new Frame("TestFileDialogDupJNIRef Test Frame"); + Button open = new Button("Open File Dialog"); + + open.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + FileDialog fd = new FileDialog(frame); + fd.setVisible(true); + } + }); + + frame.setLayout(new FlowLayout()); + frame.add(open); + frame.setSize(250, 70); + return frame; + } +} From 21f8ccf4a97313593f210f9a07e56d5ff92b7aa5 Mon Sep 17 00:00:00 2001 From: Severin Gehwolf Date: Thu, 3 Oct 2024 12:55:54 +0000 Subject: [PATCH 004/113] 8341310: Test TestJcmdWithSideCar.java should skip ACCESS_TMP_VIA_PROC_ROOT (after JDK-8327114) Reviewed-by: kevinw --- .../jtreg/containers/docker/TestJcmdWithSideCar.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java index 20883988347..5dea864f427 100644 --- a/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java +++ b/test/hotspot/jtreg/containers/docker/TestJcmdWithSideCar.java @@ -42,8 +42,8 @@ import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Paths; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.EnumSet; import java.util.List; @@ -52,7 +52,9 @@ import java.util.function.Consumer; import java.util.regex.Pattern; import java.util.stream.Collectors; + import jdk.test.lib.Container; +import jdk.test.lib.Platform; import jdk.test.lib.Utils; import jdk.test.lib.containers.docker.Common; import jdk.test.lib.containers.docker.DockerRunOptions; @@ -108,6 +110,11 @@ public static void main(String[] args) throws Exception { mainContainer.waitForMainMethodStart(TIME_TO_WAIT_FOR_MAIN_METHOD_START); for (AttachStrategy attachStrategy : EnumSet.allOf(AttachStrategy.class)) { + if (attachStrategy == AttachStrategy.ACCESS_TMP_VIA_PROC_ROOT && + elevated && !Platform.isRoot()) { + // Elevated attach via proc/root not yet supported. + continue; + } long mainProcPid = testCase01(attachStrategy, elevated); // Excluding the test case below until JDK-8228850 is fixed From eb93e6952b5d2dbe78cd9680855ac99c69b3dcb2 Mon Sep 17 00:00:00 2001 From: Alan Bateman Date: Thu, 3 Oct 2024 14:02:40 +0000 Subject: [PATCH 005/113] 8339979: VirtualThreadSchedulerMXBeanTest.testReduceParallelism fails intermittently Reviewed-by: kevinw --- .../VirtualThreadSchedulerMXBeanTest.java | 95 ++++++++++++++----- 1 file changed, 72 insertions(+), 23 deletions(-) diff --git a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java index 891f6e62e6f..b256d2b89ab 100644 --- a/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java +++ b/test/jdk/jdk/management/VirtualThreadSchedulerMXBean/VirtualThreadSchedulerMXBeanTest.java @@ -34,6 +34,8 @@ import java.lang.management.ManagementFactory; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.IntPredicate; +import java.util.function.LongPredicate; import java.util.stream.Stream; import java.util.stream.IntStream; import javax.management.MBeanServer; @@ -140,23 +142,37 @@ void testReduceParallelism(VirtualThreadSchedulerMXBean bean) throws Exception { try { // increase parallelism + saturate - int newParallelism = parallelism + 4; - bean.setParallelism(newParallelism); - IntStream.range(0, newParallelism).forEach(_ -> executor.submit(busyTask)); - awaitMountedVirtualThreadCountGte(bean, newParallelism); + int highParallelism = parallelism + 4; + bean.setParallelism(highParallelism); + IntStream.range(0, highParallelism).forEach(_ -> executor.submit(busyTask)); + + // mounted virtual thread count should increase to highParallelism. + // Sample the count at highParallelism a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountEq(bean, highParallelism); + } // reduce parallelism and workload - newParallelism = Math.clamp(parallelism / 2, 1, parallelism); - bean.setParallelism(newParallelism); + int lowParallelism = Math.clamp(parallelism / 2, 1, parallelism); + bean.setParallelism(lowParallelism); sleep.set(true); - // mounted virtual thread count should reduce - awaitMountedVirtualThreadCountLte(bean, newParallelism); - // increase workload, the mounted virtual thread count should not increase + // mounted virtual thread count should reduce to lowParallelism or less. + // Sample the count at lowParallelism or less a few times. + for (int i = 0; i < 5; i++) { + Thread.sleep(100); + awaitMountedVirtualThreadCountLte(bean, lowParallelism); + } + + // increase workload sleep.set(false); + + // mounted virtual thread count should not exceed lowParallelism. + // Sample the count at lowParallelism a few times. for (int i = 0; i < 5; i++) { Thread.sleep(100); - assertTrue(bean.getMountedVirtualThreadCount() <= newParallelism); + awaitMountedVirtualThreadCountEq(bean, lowParallelism); } } finally { @@ -230,31 +246,64 @@ void testQueuedVirtualThreadCount(VirtualThreadSchedulerMXBean bean) throws Exce * Waits for pool size >= target to be true. */ void awaitPoolSizeGte(VirtualThreadSchedulerMXBean bean, int target) throws InterruptedException { - System.err.format("await pool size >= %d ...%n", target); - while (bean.getPoolSize() < target) { - Thread.sleep(10); - } + awaitPoolSize(bean, ps -> ps >= target, ">= " + target); } /** * Waits for the mounted virtual thread count >= target to be true. */ void awaitMountedVirtualThreadCountGte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count >= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() < target) { - Thread.sleep(10); - } + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c >= target, ">= " + target); } /** * Waits for the mounted virtual thread count <= target to be true. */ void awaitMountedVirtualThreadCountLte(VirtualThreadSchedulerMXBean bean, - int target) throws InterruptedException { - System.err.format("await mounted virtual thread count <= %d ...%n", target); - while (bean.getMountedVirtualThreadCount() > target) { - Thread.sleep(10); + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c <= target, "<= " + target); + } + + /** + * Waits for the mounted virtual thread count == target to be true. + */ + void awaitMountedVirtualThreadCountEq(VirtualThreadSchedulerMXBean bean, + long target) throws InterruptedException { + awaitMountedVirtualThreadCount(bean, c -> c == target, "== " + target); + } + + /** + * Waits until evaluating the given predicte on the pool size is true. + */ + void awaitPoolSize(VirtualThreadSchedulerMXBean bean, + IntPredicate predicate, + String reason) throws InterruptedException { + int poolSize = bean.getPoolSize(); + if (!predicate.test(poolSize)) { + System.err.format("poolSize = %d, await %s ...%n", poolSize, reason); + while (!predicate.test(poolSize)) { + Thread.sleep(10); + poolSize = bean.getPoolSize(); + } + System.err.format("poolSize = %d%n", poolSize); + } + } + + /** + * Waits until evaluating the given predicte on the mounted thread count is true. + */ + void awaitMountedVirtualThreadCount(VirtualThreadSchedulerMXBean bean, + LongPredicate predicate, + String reason) throws InterruptedException { + long count = bean.getMountedVirtualThreadCount(); + if (!predicate.test(count)) { + System.err.format("mountedVirtualThreadCount = %d, await %s ...%n", count, reason); + while (!predicate.test(count)) { + Thread.sleep(10); + count = bean.getMountedVirtualThreadCount(); + } + System.err.format("mountedVirtualThreadCount = %d%n", count); } } } \ No newline at end of file From 12028000db2ef3b1c784af119c495aa3ef9590cf Mon Sep 17 00:00:00 2001 From: Shaojin Wen Date: Thu, 3 Oct 2024 14:34:05 +0000 Subject: [PATCH 006/113] 8341006: Optimize StackMapGenerator detect frames Reviewed-by: liach --- .../classfile/impl/StackMapGenerator.java | 159 ++++++++++-------- 1 file changed, 91 insertions(+), 68 deletions(-) diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java index ae983520683..0eae3c35719 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapGenerator.java @@ -1,5 +1,6 @@ /* * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, Alibaba Group Holding Limited. 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 @@ -39,7 +40,6 @@ import java.lang.constant.MethodTypeDesc; import java.util.ArrayList; import java.util.Arrays; -import java.util.BitSet; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -58,8 +58,8 @@ *

* The {@linkplain #generate() frames computation} consists of following steps: *

    - *
  1. {@linkplain #detectFrameOffsets() Detection} of mandatory stack map frames offsets: