diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e4c05acb684b7..d5958853701ca 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -384,6 +384,7 @@ jobs: - build-windows-aarch64 - test-linux-x64 - test-macos-x64 + - test-macos-aarch64 - test-windows-x64 steps: diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000..f4c5e7e67cb46 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,3 @@ +# JDK Vulnerabilities + +Please follow the process outlined in the [OpenJDK Vulnerability Policy](https://openjdk.org/groups/vulnerability/report) to disclose vulnerabilities in the JDK. diff --git a/doc/building.html b/doc/building.html index 707531553124b..c91d876246cde 100644 --- a/doc/building.html +++ b/doc/building.html @@ -614,10 +614,9 @@

clang

--with-toolchain-type=clang.

Apple Xcode

The oldest supported version of Xcode is 13.0.

-

You will need the Xcode command line developer tools to be able to -build the JDK. (Actually, only the command line tools are -needed, not the IDE.) The simplest way to install these is to run:

-
xcode-select --install
+

You will need to download Xcode either from the App Store or specific +versions can be easily located via the Xcode Releases website.

When updating Xcode, it is advisable to keep an older version for building the JDK. To use a specific version of Xcode you have multiple options:

diff --git a/doc/building.md b/doc/building.md index 51ac0cad7d98b..47ad9e7c72b4c 100644 --- a/doc/building.md +++ b/doc/building.md @@ -422,13 +422,9 @@ To use clang instead of gcc on Linux, use `--with-toolchain-type=clang`. The oldest supported version of Xcode is 13.0. -You will need the Xcode command line developer tools to be able to build the -JDK. (Actually, *only* the command line tools are needed, not the IDE.) The -simplest way to install these is to run: - -``` -xcode-select --install -``` +You will need to download Xcode either from the App Store or specific versions +can be easily located via the [Xcode Releases](https://xcodereleases.com) +website. When updating Xcode, it is advisable to keep an older version for building the JDK. To use a specific version of Xcode you have multiple options: diff --git a/src/hotspot/cpu/aarch64/aarch64.ad b/src/hotspot/cpu/aarch64/aarch64.ad index fced9cfc35e57..39eae43a287e7 100644 --- a/src/hotspot/cpu/aarch64/aarch64.ad +++ b/src/hotspot/cpu/aarch64/aarch64.ad @@ -1244,7 +1244,7 @@ source %{ // r27 is not allocatable when compressed oops is on and heapbase is not // zero, compressed klass pointers doesn't use r27 after JDK-8234794 - if (UseCompressedOops && (CompressedOops::ptrs_base() != nullptr)) { + if (UseCompressedOops && (CompressedOops::base() != nullptr)) { _NO_SPECIAL_REG32_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); _NO_SPECIAL_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); _NO_SPECIAL_PTR_REG_mask.Remove(OptoReg::as_OptoReg(r27->as_VMReg())); diff --git a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp index cd834969e1a4f..fcec3ae64fde8 100644 --- a/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/gc/z/zAddress_aarch64.cpp @@ -93,7 +93,7 @@ static size_t probe_valid_max_address_bit() { } size_t ZPlatformAddressOffsetBits() { - const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; + static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); diff --git a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp index 08b69b34a9462..c5c02619d446e 100644 --- a/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/macroAssembler_aarch64.cpp @@ -2967,7 +2967,7 @@ void MacroAssembler::verify_heapbase(const char* msg) { if (CheckCompressedOops) { Label ok; push(1 << rscratch1->encoding(), sp); // cmpptr trashes rscratch1 - cmpptr(rheapbase, ExternalAddress(CompressedOops::ptrs_base_addr())); + cmpptr(rheapbase, ExternalAddress(CompressedOops::base_addr())); br(Assembler::EQ, ok); stop(msg); bind(ok); @@ -3133,9 +3133,9 @@ void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { if (Universe::is_fully_initialized()) { - mov(rheapbase, CompressedOops::ptrs_base()); + mov(rheapbase, CompressedOops::base()); } else { - lea(rheapbase, ExternalAddress(CompressedOops::ptrs_base_addr())); + lea(rheapbase, ExternalAddress(CompressedOops::base_addr())); ldr(rheapbase, Address(rheapbase)); } } diff --git a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp index 3117c75149854..1b02108b00f94 100644 --- a/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/sharedRuntime_aarch64.cpp @@ -49,6 +49,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/formatBuffer.hpp" diff --git a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp index 38d48b86f23b0..3210789bbbdfa 100644 --- a/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp +++ b/src/hotspot/cpu/aarch64/templateInterpreterGenerator_aarch64.cpp @@ -69,12 +69,6 @@ int TemplateInterpreter::InterpreterCodeSize = 200 * 1024; #define __ _masm-> -//----------------------------------------------------------------------------- - -extern "C" void entry(CodeBuffer*); - -//----------------------------------------------------------------------------- - address TemplateInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); diff --git a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp index 7648e5c5d9260..7c1f3aafe7d52 100644 --- a/src/hotspot/cpu/arm/sharedRuntime_arm.cpp +++ b/src/hotspot/cpu/arm/sharedRuntime_arm.cpp @@ -38,6 +38,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/safepointMechanism.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/powerOfTwo.hpp" diff --git a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp index c05e97a4e9aa3..83fad376d292a 100644 --- a/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c1_MacroAssembler_ppc.cpp @@ -92,7 +92,7 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(Roop, Rmark, Rscratch, slow_int); + lightweight_lock(Rbox, Roop, Rmark, Rscratch, slow_int); } else if (LockingMode == LM_LEGACY) { // ... and mark it unlocked. ori(Rmark, Rmark, markWord::unlocked_value); diff --git a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp index cc69c0abe361f..1147c3b42b25f 100644 --- a/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/c2_MacroAssembler_ppc.cpp @@ -39,12 +39,12 @@ void C2_MacroAssembler::fast_lock_lightweight(ConditionRegister flag, Register obj, Register box, Register tmp1, Register tmp2, Register tmp3) { - compiler_fast_lock_lightweight_object(flag, obj, tmp1, tmp2, tmp3); + compiler_fast_lock_lightweight_object(flag, obj, box, tmp1, tmp2, tmp3); } void C2_MacroAssembler::fast_unlock_lightweight(ConditionRegister flag, Register obj, Register box, Register tmp1, Register tmp2, Register tmp3) { - compiler_fast_unlock_lightweight_object(flag, obj, tmp1, tmp2, tmp3); + compiler_fast_unlock_lightweight_object(flag, obj, box, tmp1, tmp2, tmp3); } // Intrinsics for CompactStrings diff --git a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp index 136fd7a8ad1cd..ddeb9adf0a9ae 100644 --- a/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp +++ b/src/hotspot/cpu/ppc/gc/z/zAddress_ppc.cpp @@ -90,7 +90,7 @@ static size_t probe_valid_max_address_bit() { } size_t ZPlatformAddressOffsetBits() { - const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; + static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); diff --git a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp index a29e0810d52ca..aa77f0169ea1a 100644 --- a/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp +++ b/src/hotspot/cpu/ppc/interp_masm_ppc_64.cpp @@ -968,7 +968,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(object, header, tmp, slow_case); + lightweight_lock(monitor, object, header, tmp, slow_case); b(count_locking); } else if (LockingMode == LM_LEGACY) { // Load markWord from object into header. diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp index 8449d74d8a861..a8635af9582d1 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.cpp @@ -2730,9 +2730,9 @@ void MacroAssembler::compiler_fast_unlock_object(ConditionRegister flag, Registe bind(failure); } -void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register tmp1, - Register tmp2, Register tmp3) { - assert_different_registers(obj, tmp1, tmp2, tmp3); +void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister flag, Register obj, Register box, + Register tmp1, Register tmp2, Register tmp3) { + assert_different_registers(obj, box, tmp1, tmp2, tmp3); assert(flag == CCR0, "bad condition register"); // Handle inflated monitor. @@ -2742,11 +2742,17 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla // Finish fast lock unsuccessfully. MUST branch to with flag == EQ Label slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + li(tmp1, 0); + std(tmp1, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); lbz(tmp1, in_bytes(Klass::misc_flags_offset()), tmp1); - testbitdi(flag, R0, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); - bne(flag, slow_path); + testbitdi(CCR0, R0, tmp1, exact_log2(KlassFlags::_misc_is_value_based_class)); + bne(CCR0, slow_path); } const Register mark = tmp1; @@ -2761,8 +2767,8 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla // Check if lock-stack is full. lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread); - cmplwi(flag, top, LockStack::end_offset() - 1); - bgt(flag, slow_path); + cmplwi(CCR0, top, LockStack::end_offset() - 1); + bgt(CCR0, slow_path); // The underflow check is elided. The recursive check will always fail // when the lock stack is empty because of the _bad_oop_sentinel field. @@ -2770,19 +2776,19 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla // Check if recursive. subi(t, top, oopSize); ldx(t, R16_thread, t); - cmpd(flag, obj, t); - beq(flag, push); + cmpd(CCR0, obj, t); + beq(CCR0, push); // Check for monitor (0b10) or locked (0b00). ld(mark, oopDesc::mark_offset_in_bytes(), obj); andi_(t, mark, markWord::lock_mask_in_place); - cmpldi(flag, t, markWord::unlocked_value); - bgt(flag, inflated); - bne(flag, slow_path); + cmpldi(CCR0, t, markWord::unlocked_value); + bgt(CCR0, inflated); + bne(CCR0, slow_path); // Not inflated. - // Try to lock. Transition lock bits 0b00 => 0b01 + // Try to lock. Transition lock bits 0b01 => 0b00 assert(oopDesc::mark_offset_in_bytes() == 0, "required to avoid a lea"); atomically_flip_locked_state(/* is_unlock */ false, obj, mark, slow_path, MacroAssembler::MemBarAcq); @@ -2797,38 +2803,84 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla { // Handle inflated monitor. bind(inflated); + // mark contains the tagged ObjectMonitor*. + const uintptr_t monitor_tag = markWord::monitor_value; + const Register monitor = mark; + const Register owner_addr = tmp2; + Label monitor_locked; + if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; - const Register owner_addr = tmp2; + // Compute owner address. + addi(owner_addr, mark, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); + } else { + Label monitor_found; + Register cache_addr = tmp2; + + // Load cache address + addi(cache_addr, R16_thread, in_bytes(JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + ld(tmp3, 0, cache_addr); + cmpd(CCR0, tmp3, obj); + beq(CCR0, monitor_found); + addi(cache_addr, cache_addr, in_bytes(OMCache::oop_to_oop_difference())); + } + + Label loop; + + // Search for obj in cache. + bind(loop); + + // Check for match. + ld(tmp3, 0, cache_addr); + cmpd(CCR0, tmp3, obj); + beq(CCR0, monitor_found); + + // Search until null encountered, guaranteed _null_sentinel at end. + addi(cache_addr, cache_addr, in_bytes(OMCache::oop_to_oop_difference())); + cmpdi(CCR1, tmp3, 0); + bne(CCR1, loop); + // Cache Miss, CCR0.NE set from cmp above + b(slow_path); + + bind(monitor_found); + ld(monitor, in_bytes(OMCache::oop_to_monitor_difference()), cache_addr); // Compute owner address. - addi(owner_addr, tagged_monitor, in_bytes(ObjectMonitor::owner_offset()) - monitor_tag); - - // CAS owner (null => current thread). - cmpxchgd(/*flag=*/flag, - /*current_value=*/t, - /*compare_value=*/(intptr_t)0, - /*exchange_value=*/R16_thread, - /*where=*/owner_addr, - MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, - MacroAssembler::cmpxchgx_hint_acquire_lock()); - beq(flag, locked); - - // Check if recursive. - cmpd(flag, t, R16_thread); - bne(flag, slow_path); - - // Recursive. + addi(owner_addr, monitor, in_bytes(ObjectMonitor::owner_offset())); + } + + // CAS owner (null => current thread). + cmpxchgd(/*flag=*/CCR0, + /*current_value=*/t, + /*compare_value=*/(intptr_t)0, + /*exchange_value=*/R16_thread, + /*where=*/owner_addr, + MacroAssembler::MemBarRel | MacroAssembler::MemBarAcq, + MacroAssembler::cmpxchgx_hint_acquire_lock()); + beq(CCR0, monitor_locked); + + // Check if recursive. + cmpd(CCR0, t, R16_thread); + bne(CCR0, slow_path); + + // Recursive. + if (!UseObjectMonitorTable) { + assert_different_registers(tmp1, owner_addr); ld(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); addi(tmp1, tmp1, 1); std(tmp1, in_bytes(ObjectMonitor::recursions_offset() - ObjectMonitor::owner_offset()), owner_addr); } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - crxor(flag, Assembler::equal, flag, Assembler::equal); - b(slow_path); + assert_different_registers(tmp2, monitor); + ld(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor); + addi(tmp2, tmp2, 1); + std(tmp2, in_bytes(ObjectMonitor::recursions_offset()), monitor); + } + + bind(monitor_locked); + if (UseObjectMonitorTable) { + std(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box); } } @@ -2838,21 +2890,21 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(ConditionRegister fla #ifdef ASSERT // Check that locked label is reached with flag == EQ. Label flag_correct; - beq(flag, flag_correct); + beq(CCR0, flag_correct); stop("Fast Lock Flag != EQ"); #endif bind(slow_path); #ifdef ASSERT // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); + bne(CCR0, flag_correct); stop("Fast Lock Flag != NE"); bind(flag_correct); #endif // C2 uses the value of flag (NE vs EQ) to determine the continuation. } -void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register obj, Register tmp1, - Register tmp2, Register tmp3) { +void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register obj, Register box, + Register tmp1, Register tmp2, Register tmp3) { assert_different_registers(obj, tmp1, tmp2, tmp3); assert(flag == CCR0, "bad condition register"); @@ -2874,9 +2926,9 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread); subi(top, top, oopSize); ldx(t, R16_thread, top); - cmpd(flag, obj, t); + cmpd(CCR0, obj, t); // Top of lock stack was not obj. Must be monitor. - bne(flag, inflated_load_monitor); + bne(CCR0, inflated_load_monitor); // Pop lock-stack. DEBUG_ONLY(li(t, 0);) @@ -2889,8 +2941,8 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f // Check if recursive. subi(t, top, oopSize); ldx(t, R16_thread, t); - cmpd(flag, obj, t); - beq(flag, unlocked); + cmpd(CCR0, obj, t); + beq(CCR0, unlocked); // Not recursive. @@ -2941,62 +2993,62 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f cmplwi(CCR0, top, in_bytes(JavaThread::lock_stack_base_offset())); blt(CCR0, check_done); ldx(t, R16_thread, top); - cmpd(flag, obj, t); - bne(flag, inflated); + cmpd(CCR0, obj, t); + bne(CCR0, inflated); stop("Fast Unlock lock on stack"); bind(check_done); #endif - if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; - const uintptr_t monitor_tag = markWord::monitor_value; + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; + const uintptr_t monitor_tag = markWord::monitor_value; + if (!UseObjectMonitorTable) { // Untag the monitor. subi(monitor, mark, monitor_tag); + } else { + ld(monitor, BasicLock::object_monitor_cache_offset_in_bytes(), box); + // null check with Flags == NE, no valid pointer below alignof(ObjectMonitor*) + cmpldi(CCR0, monitor, checked_cast(alignof(ObjectMonitor*))); + blt(CCR0, slow_path); + } - const Register recursions = tmp2; - Label not_recursive; + const Register recursions = tmp2; + Label not_recursive; - // Check if recursive. - ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - addic_(recursions, recursions, -1); - blt(CCR0, not_recursive); + // Check if recursive. + ld(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + addic_(recursions, recursions, -1); + blt(CCR0, not_recursive); - // Recursive unlock. - std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); - crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); - b(unlocked); + // Recursive unlock. + std(recursions, in_bytes(ObjectMonitor::recursions_offset()), monitor); + crorc(CCR0, Assembler::equal, CCR0, Assembler::equal); + b(unlocked); - bind(not_recursive); + bind(not_recursive); - Label release_; - const Register t2 = tmp2; + Label release_; + const Register t2 = tmp2; - // Check if the entry lists are empty. - ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); - ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); - orr(t, t, t2); - cmpdi(flag, t, 0); - beq(flag, release_); + // Check if the entry lists are empty. + ld(t, in_bytes(ObjectMonitor::EntryList_offset()), monitor); + ld(t2, in_bytes(ObjectMonitor::cxq_offset()), monitor); + orr(t, t, t2); + cmpdi(CCR0, t, 0); + beq(CCR0, release_); - // The owner may be anonymous and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); - b(slow_path); + // The owner may be anonymous and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + std(R16_thread, in_bytes(ObjectMonitor::owner_offset()), monitor); + b(slow_path); - bind(release_); - // Set owner to null. - release(); - // t contains 0 - std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); - } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - crxor(flag, Assembler::equal, flag, Assembler::equal); - b(slow_path); - } + bind(release_); + // Set owner to null. + release(); + // t contains 0 + std(t, in_bytes(ObjectMonitor::owner_offset()), monitor); } bind(unlocked); @@ -3005,13 +3057,13 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(ConditionRegister f #ifdef ASSERT // Check that unlocked label is reached with flag == EQ. Label flag_correct; - beq(flag, flag_correct); + beq(CCR0, flag_correct); stop("Fast Lock Flag != EQ"); #endif bind(slow_path); #ifdef ASSERT // Check that slow_path label is reached with flag == NE. - bne(flag, flag_correct); + bne(CCR0, flag_correct); stop("Fast Lock Flag != NE"); bind(flag_correct); #endif @@ -4640,15 +4692,21 @@ void MacroAssembler::atomically_flip_locked_state(bool is_unlock, Register obj, // // - obj: the object to be locked // - t1, t2: temporary register -void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, Label& slow) { +void MacroAssembler::lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, t1, t2); + assert_different_registers(box, obj, t1, t2); Label push; const Register top = t1; const Register mark = t2; const Register t = R0; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + li(t, 0); + std(t, in_bytes(BasicObjectLock::lock_offset()) + BasicLock::object_monitor_cache_offset_in_bytes(), box); + } + // Check if the lock-stack is full. lwz(top, in_bytes(JavaThread::lock_stack_top_offset()), R16_thread); cmplwi(CCR0, top, LockStack::end_offset()); @@ -4669,7 +4727,7 @@ void MacroAssembler::lightweight_lock(Register obj, Register t1, Register t2, La andi_(t, t, markWord::lock_mask_in_place); bne(CCR0, slow); - // Try to lock. Transition lock bits 0b00 => 0b01 + // Try to lock. Transition lock bits 0b01 => 0b00 atomically_flip_locked_state(/* is_unlock */ false, obj, mark, slow, MacroAssembler::MemBarAcq); bind(push); diff --git a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp index 03ad37a4fb04a..224e7bff99541 100644 --- a/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp +++ b/src/hotspot/cpu/ppc/macroAssembler_ppc.hpp @@ -654,7 +654,7 @@ class MacroAssembler: public Assembler { void inc_held_monitor_count(Register tmp); void dec_held_monitor_count(Register tmp); void atomically_flip_locked_state(bool is_unlock, Register obj, Register tmp, Label& failed, int semantics); - void lightweight_lock(Register obj, Register t1, Register t2, Label& slow); + void lightweight_lock(Register box, Register obj, Register t1, Register t2, Label& slow); void lightweight_unlock(Register obj, Register t1, Label& slow); // allocation (for C1) @@ -675,11 +675,11 @@ class MacroAssembler: public Assembler { void compiler_fast_unlock_object(ConditionRegister flag, Register oop, Register box, Register tmp1, Register tmp2, Register tmp3); - void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register tmp1, - Register tmp2, Register tmp3); + void compiler_fast_lock_lightweight_object(ConditionRegister flag, Register oop, Register box, + Register tmp1, Register tmp2, Register tmp3); - void compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register oop, Register tmp1, - Register tmp2, Register tmp3); + void compiler_fast_unlock_lightweight_object(ConditionRegister flag, Register oop, Register box, + Register tmp1, Register tmp2, Register tmp3); // Check if safepoint requested and if so branch void safepoint_poll(Label& slow_path, Register temp, bool at_return, bool in_nmethod); diff --git a/src/hotspot/cpu/ppc/ppc.ad b/src/hotspot/cpu/ppc/ppc.ad index e7e066ebcc6d3..612b7bf898c08 100644 --- a/src/hotspot/cpu/ppc/ppc.ad +++ b/src/hotspot/cpu/ppc/ppc.ad @@ -12106,10 +12106,10 @@ instruct cmpFastUnlock(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp ins_pipe(pipe_class_compare); %} -instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2) %{ +instruct cmpFastLockLightweight(flagsRegCR0 crx, iRegPdst oop, iRegPdst box, iRegPdst tmp1, iRegPdst tmp2, flagsRegCR1 cr1) %{ predicate(LockingMode == LM_LIGHTWEIGHT); match(Set crx (FastLock oop box)); - effect(TEMP tmp1, TEMP tmp2); + effect(TEMP tmp1, TEMP tmp2, KILL cr1); format %{ "FASTLOCK $oop, $box, $tmp1, $tmp2" %} ins_encode %{ diff --git a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp index 5cf5f7cf73e03..aa8ae6070b6a6 100644 --- a/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp +++ b/src/hotspot/cpu/ppc/sharedRuntime_ppc.cpp @@ -2399,7 +2399,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for locking. if (LockingMode == LM_LIGHTWEIGHT) { // fast_lock kills r_temp_1, r_temp_2, r_temp_3. - __ compiler_fast_lock_lightweight_object(CCR0, r_oop, r_temp_1, r_temp_2, r_temp_3); + __ compiler_fast_lock_lightweight_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); } else { // fast_lock kills r_temp_1, r_temp_2, r_temp_3. __ compiler_fast_lock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); @@ -2605,7 +2605,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for unlocking. if (LockingMode == LM_LIGHTWEIGHT) { - __ compiler_fast_unlock_lightweight_object(CCR0, r_oop, r_temp_1, r_temp_2, r_temp_3); + __ compiler_fast_unlock_lightweight_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); } else { __ compiler_fast_unlock_object(CCR0, r_oop, r_box, r_temp_1, r_temp_2, r_temp_3); } diff --git a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp index 03dca2aeb9b7b..cf3dd4cbd34c0 100644 --- a/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp +++ b/src/hotspot/cpu/ppc/templateInterpreterGenerator_ppc.cpp @@ -1078,6 +1078,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M case Interpreter::java_lang_math_sin : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); break; case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break; case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break; + case Interpreter::java_lang_math_tanh : /* run interpreted */ break; case Interpreter::java_lang_math_abs : /* run interpreted */ break; case Interpreter::java_lang_math_sqrt : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); break; case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break; diff --git a/src/hotspot/cpu/riscv/assembler_riscv.hpp b/src/hotspot/cpu/riscv/assembler_riscv.hpp index 98ab86bf72eb6..d1021d9e283d2 100644 --- a/src/hotspot/cpu/riscv/assembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/assembler_riscv.hpp @@ -705,6 +705,16 @@ class Assembler : public AbstractAssembler { emit(insn); } + void fencei() { + unsigned insn = 0; + patch((address)&insn, 6, 0, 0b0001111); // opcode + patch((address)&insn, 11, 7, 0b00000); // rd + patch((address)&insn, 14, 12, 0b001); // func + patch((address)&insn, 19, 15, 0b00000); // rs1 + patch((address)&insn, 31, 20, 0b000000000000); // fm + emit(insn); + } + #define INSN(NAME, op, funct3, funct7) \ void NAME() { \ unsigned insn = 0; \ diff --git a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp index ef13676b02ed8..df111723d56b6 100644 --- a/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zAddress_riscv.cpp @@ -92,7 +92,7 @@ static size_t probe_valid_max_address_bit() { } size_t ZPlatformAddressOffsetBits() { - const static size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; + static const size_t valid_max_address_offset_bits = probe_valid_max_address_bit() + 1; const size_t max_address_offset_bits = valid_max_address_offset_bits - 3; const size_t min_address_offset_bits = max_address_offset_bits - 2; const size_t address_offset = round_up_power_of_2(MaxHeapSize * ZVirtualToPhysicalRatio); diff --git a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp index 8fbeaa45371d1..cbb918ade00fe 100644 --- a/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/gc/z/zBarrierSetAssembler_riscv.cpp @@ -636,8 +636,20 @@ void ZBarrierSetAssembler::patch_barrier_relocation(address addr, int format) { ShouldNotReachHere(); } - // A full fence is generated before icache_flush by default in invalidate_word - ICache::invalidate_range(addr, bytes); + // If we are using UseCtxFencei no ICache invalidation is needed here. + // Instead every hart will preform an fence.i either by a Java thread + // (due to patching epoch will take it to slow path), + // or by the kernel when a Java thread is moved to a hart. + // The instruction streams changes must only happen before the disarm of + // the nmethod barrier. Where the disarm have a leading full two way fence. + // If this is performed during a safepoint, all Java threads will emit a fence.i + // before transitioning to 'Java', e.g. leaving native or the safepoint wait barrier. + if (!UseCtxFencei) { + // ICache invalidation is a serialization point. + // The above patching of instructions happens before the invalidation. + // Hence it have a leading full two way fence (wr, wr). + ICache::invalidate_range(addr, bytes); + } } #ifdef COMPILER2 diff --git a/src/hotspot/cpu/riscv/globals_riscv.hpp b/src/hotspot/cpu/riscv/globals_riscv.hpp index c2585f2d1618d..dd31de14704ab 100644 --- a/src/hotspot/cpu/riscv/globals_riscv.hpp +++ b/src/hotspot/cpu/riscv/globals_riscv.hpp @@ -122,6 +122,8 @@ define_pd_global(intx, InlineSmallCode, 1000); product(bool, UseRVVForBigIntegerShiftIntrinsics, true, \ "Use RVV instructions for left/right shift of BigInteger") \ product(bool, UseTrampolines, false, EXPERIMENTAL, \ - "Far calls uses jal to trampoline.") + "Far calls uses jal to trampoline.") \ + product(bool, UseCtxFencei, false, EXPERIMENTAL, \ + "Use PR_RISCV_CTX_SW_FENCEI_ON to avoid explicit icache flush") #endif // CPU_RISCV_GLOBALS_RISCV_HPP diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp index de0df45bbf507..32a446959a246 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.cpp @@ -1455,6 +1455,7 @@ void MacroAssembler::update_word_crc32(Register crc, Register v, Register tmp1, } +#ifdef COMPILER2 // This improvement (vectorization) is based on java.base/share/native/libzip/zlib/zcrc32.c. // To make it, following steps are taken: // 1. in zcrc32.c, modify N to 16 and related code, @@ -1550,6 +1551,7 @@ void MacroAssembler::vector_update_crc32(Register crc, Register buf, Register le addi(buf, buf, N*4); } } +#endif // COMPILER2 /** * @param crc register containing existing CRC (32-bit) @@ -1576,11 +1578,13 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, add(table2, table0, 2*single_table_size*sizeof(juint), tmp1); add(table3, table2, 1*single_table_size*sizeof(juint), tmp1); +#ifdef COMPILER2 if (UseRVV) { const int64_t tmp_limit = MaxVectorSize >= 32 ? unroll_words*3 : unroll_words*5; mv(tmp1, tmp_limit); bge(len, tmp1, L_vector_entry); } +#endif // COMPILER2 subw(len, len, unroll_words); bge(len, zr, L_unroll_loop_entry); @@ -1643,6 +1647,7 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, andi(tmp2, tmp2, right_8_bits); update_byte_crc32(crc, tmp2, table0); +#ifdef COMPILER2 // put vector code here, otherwise "offset is too large" error occurs. if (UseRVV) { j(L_exit); // only need to jump exit when UseRVV == true, it's a jump from end of block `L_by1_loop`. @@ -1655,6 +1660,7 @@ void MacroAssembler::kernel_crc32(Register crc, Register buf, Register len, addiw(len, len, 4); bgt(len, zr, L_by1_loop); } +#endif // COMPILER2 bind(L_exit); andn(crc, tmp5, crc); @@ -1970,9 +1976,9 @@ int MacroAssembler::patch_oop(address insn_addr, address o) { void MacroAssembler::reinit_heapbase() { if (UseCompressedOops) { if (Universe::is_fully_initialized()) { - mv(xheapbase, CompressedOops::ptrs_base()); + mv(xheapbase, CompressedOops::base()); } else { - ExternalAddress target(CompressedOops::ptrs_base_addr()); + ExternalAddress target(CompressedOops::base_addr()); relocate(target.rspec(), [&] { int32_t offset; la(xheapbase, target.target(), offset); @@ -2085,23 +2091,11 @@ void MacroAssembler::addw(Register Rd, Register Rn, int32_t increment, Register } void MacroAssembler::sub(Register Rd, Register Rn, int64_t decrement, Register temp) { - if (is_simm12(-decrement)) { - addi(Rd, Rn, -decrement); - } else { - assert_different_registers(Rn, temp); - li(temp, decrement); - sub(Rd, Rn, temp); - } + add(Rd, Rn, -decrement, temp); } void MacroAssembler::subw(Register Rd, Register Rn, int32_t decrement, Register temp) { - if (is_simm12(-decrement)) { - addiw(Rd, Rn, -decrement); - } else { - assert_different_registers(Rn, temp); - li(temp, decrement); - subw(Rd, Rn, temp); - } + addw(Rd, Rn, -decrement, temp); } void MacroAssembler::andrw(Register Rd, Register Rs1, Register Rs2) { @@ -3171,6 +3165,13 @@ void MacroAssembler::membar(uint32_t order_constraint) { } } +void MacroAssembler::cmodx_fence() { + BLOCK_COMMENT("cmodx fence"); + if (VM_Version::supports_fencei_barrier()) { + Assembler::fencei(); + } +} + // Form an address from base + offset in Rd. Rd my or may not // actually be used: you must use the Address that is returned. It // is up to you to ensure that the shift provided matches the size diff --git a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp index 43d9dc387ca20..fd174f241eb0b 100644 --- a/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp +++ b/src/hotspot/cpu/riscv/macroAssembler_riscv.hpp @@ -431,6 +431,8 @@ class MacroAssembler: public Assembler { } } + void cmodx_fence(); + void pause() { Assembler::fence(w, 0); } @@ -1319,11 +1321,12 @@ class MacroAssembler: public Assembler { Register table0, Register table1, Register table2, Register table3, bool upper); void update_byte_crc32(Register crc, Register val, Register table); + +#ifdef COMPILER2 void vector_update_crc32(Register crc, Register buf, Register len, Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register table0, Register table3); -#ifdef COMPILER2 void mul_add(Register out, Register in, Register offset, Register len, Register k, Register tmp); void wide_mul(Register prod_lo, Register prod_hi, Register n, Register m); @@ -1353,7 +1356,7 @@ class MacroAssembler: public Assembler { Register tmp1, Register tmp2, Register tmp3, Register tmp4, Register tmp5, Register tmp6, Register product_hi); -#endif +#endif // COMPILER2 void inflate_lo32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); void inflate_hi32(Register Rd, Register Rs, Register tmp1 = t0, Register tmp2 = t1); diff --git a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp index d0903c96e2271..18b4302c7e68e 100644 --- a/src/hotspot/cpu/riscv/relocInfo_riscv.cpp +++ b/src/hotspot/cpu/riscv/relocInfo_riscv.cpp @@ -55,7 +55,21 @@ void Relocation::pd_set_data_value(address x, bool verify_only) { bytes = MacroAssembler::pd_patch_instruction_size(addr(), x); break; } - ICache::invalidate_range(addr(), bytes); + + // If we are using UseCtxFencei no ICache invalidation is needed here. + // Instead every hart will preform an fence.i either by a Java thread + // (due to patching epoch will take it to slow path), + // or by the kernel when a Java thread is moved to a hart. + // The instruction streams changes must only happen before the disarm of + // the nmethod barrier. Where the disarm have a leading full two way fence. + // If this is performed during a safepoint, all Java threads will emit a fence.i + // before transitioning to 'Java', e.g. leaving native or the safepoint wait barrier. + if (!UseCtxFencei) { + // ICache invalidation is a serialization point. + // The above patching of instructions happens before the invalidation. + // Hence it have a leading full two way fence (wr, wr). + ICache::invalidate_range(addr(), bytes); + } } address Relocation::pd_call_destination(address orig_addr) { diff --git a/src/hotspot/cpu/riscv/riscv_v.ad b/src/hotspot/cpu/riscv/riscv_v.ad index 54947f6bf9a19..510c0ff5d4646 100644 --- a/src/hotspot/cpu/riscv/riscv_v.ad +++ b/src/hotspot/cpu/riscv/riscv_v.ad @@ -4895,11 +4895,10 @@ instruct gather_loadS(vReg dst, indirect mem, vReg idx) %{ effect(TEMP_DEF dst); format %{ "gather_loadS $dst, $mem, $idx" %} ins_encode %{ - __ vmv1r_v(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), (int)sew); + __ vsll_vi(as_VectorRegister($dst$$reg), as_VectorRegister($idx$$reg), (int)sew); __ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base), as_VectorRegister($dst$$reg)); %} @@ -4929,11 +4928,10 @@ instruct gather_loadS_masked(vReg dst, indirect mem, vReg idx, vRegMask_V0 v0, v effect(TEMP_DEF dst, TEMP tmp); format %{ "gather_loadS_masked $dst, $mem, $idx, $v0\t# KILL $tmp" %} ins_encode %{ - __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this); Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this)); - __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew); __ vxor_vv(as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg), as_VectorRegister($dst$$reg)); __ vluxei32_v(as_VectorRegister($dst$$reg), as_Register($mem$$base), @@ -4969,11 +4967,10 @@ instruct scatter_storeS(indirect mem, vReg src, vReg idx, vReg tmp) %{ effect(TEMP tmp); format %{ "scatter_storeS $mem, $idx, $src\t# KILL $tmp" %} ins_encode %{ - __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this, $src); Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this, $src)); - __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew); __ vsuxei32_v(as_VectorRegister($src$$reg), as_Register($mem$$base), as_VectorRegister($tmp$$reg)); %} @@ -5003,11 +5000,10 @@ instruct scatter_storeS_masked(indirect mem, vReg src, vReg idx, vRegMask_V0 v0, effect(TEMP tmp); format %{ "scatter_storeS_masked $mem, $idx, $src, $v0\t# KILL $tmp" %} ins_encode %{ - __ vmv1r_v(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg)); BasicType bt = Matcher::vector_element_basic_type(this, $src); Assembler::SEW sew = Assembler::elemtype_to_sew(bt); __ vsetvli_helper(bt, Matcher::vector_length(this, $src)); - __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($tmp$$reg), (int)sew); + __ vsll_vi(as_VectorRegister($tmp$$reg), as_VectorRegister($idx$$reg), (int)sew); __ vsuxei32_v(as_VectorRegister($src$$reg), as_Register($mem$$base), as_VectorRegister($tmp$$reg), Assembler::v0_t); %} diff --git a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp index 9162c1d520027..d4ec76da94315 100644 --- a/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp +++ b/src/hotspot/cpu/riscv/stubGenerator_riscv.cpp @@ -2428,6 +2428,14 @@ class StubGenerator: public StubCodeGenerator { __ la(t1, ExternalAddress(bs_asm->patching_epoch_addr())); __ lwu(t1, t1); __ sw(t1, thread_epoch_addr); + // There are two ways this can work: + // - The writer did system icache shootdown after the instruction stream update. + // Hence do nothing. + // - The writer trust us to make sure our icache is in sync before entering. + // Hence use cmodx fence (fence.i, may change). + if (UseCtxFencei) { + __ cmodx_fence(); + } __ membar(__ LoadLoad); } @@ -5491,9 +5499,7 @@ class StubGenerator: public StubCodeGenerator { Register stepSrcM2 = doff; Register stepDst = isURL; Register size = x29; // t4 - Register minusOne = x30; // t5 - __ mv(minusOne, -1); __ mv(size, MaxVectorSize * 2); __ mv(stepSrcM1, MaxVectorSize * 4); __ slli(stepSrcM2, stepSrcM1, 1); @@ -5513,7 +5519,8 @@ class StubGenerator: public StubCodeGenerator { __ sub(length, length, stepSrcM2); // error check - __ bne(failedIdx, minusOne, Exit); + // valid value of failedIdx can only be -1 when < 0 + __ bgez(failedIdx, Exit); __ bge(length, stepSrcM2, ProcessM2); @@ -5533,7 +5540,8 @@ class StubGenerator: public StubCodeGenerator { __ sub(length, length, stepSrcM1); // error check - __ bne(failedIdx, minusOne, Exit); + // valid value of failedIdx can only be -1 when < 0 + __ bgez(failedIdx, Exit); __ BIND(ProcessScalar); __ beqz(length, Exit); diff --git a/src/hotspot/cpu/riscv/vm_version_riscv.hpp b/src/hotspot/cpu/riscv/vm_version_riscv.hpp index bd4bfe86d9bf7..8fdde0094f40d 100644 --- a/src/hotspot/cpu/riscv/vm_version_riscv.hpp +++ b/src/hotspot/cpu/riscv/vm_version_riscv.hpp @@ -285,6 +285,7 @@ class VM_Version : public Abstract_VM_Version { // RISCV64 supports fast class initialization checks static bool supports_fast_class_init_checks() { return true; } + static bool supports_fencei_barrier() { return ext_Zifencei.enabled(); } }; #endif // CPU_RISCV_VM_VERSION_RISCV_HPP diff --git a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp index f3fa19ddb31e0..f6dd20db3d67f 100644 --- a/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c1_MacroAssembler_s390.cpp @@ -79,7 +79,7 @@ void C1_MacroAssembler::lock_object(Register Rmark, Register Roop, Register Rbox assert(LockingMode != LM_MONITOR, "LM_MONITOR is already handled, by emit_lock()"); if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(Roop, Rmark, tmp, slow_case); + lightweight_lock(Rbox, Roop, Rmark, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { NearLabel done; diff --git a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp index 3641d82dabea9..025ef4c8915cd 100644 --- a/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/c2_MacroAssembler_s390.cpp @@ -34,12 +34,12 @@ #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") void C2_MacroAssembler::fast_lock_lightweight(Register obj, Register box, Register temp1, Register temp2) { - compiler_fast_lock_lightweight_object(obj, temp1, temp2); + compiler_fast_lock_lightweight_object(obj, box, temp1, temp2); } void C2_MacroAssembler::fast_unlock_lightweight(Register obj, Register box, Register temp1, Register temp2) { - compiler_fast_unlock_lightweight_object(obj, temp1, temp2); + compiler_fast_unlock_lightweight_object(obj, box, temp1, temp2); } //------------------------------------------------------ diff --git a/src/hotspot/cpu/s390/downcallLinker_s390.cpp b/src/hotspot/cpu/s390/downcallLinker_s390.cpp index 383a32448745c..85ddc5bf18548 100644 --- a/src/hotspot/cpu/s390/downcallLinker_s390.cpp +++ b/src/hotspot/cpu/s390/downcallLinker_s390.cpp @@ -36,8 +36,8 @@ #define __ _masm-> -static const int native_invoker_code_base_size = 512; -static const int native_invoker_size_per_args = 8; +static const int native_invoker_code_base_size = 384; +static const int native_invoker_size_per_args = 12; RuntimeStub* DowncallLinker::make_downcall_stub(BasicType* signature, int num_args, diff --git a/src/hotspot/cpu/s390/interp_masm_s390.cpp b/src/hotspot/cpu/s390/interp_masm_s390.cpp index e56beaa9f569c..d00b6c3e2cc2e 100644 --- a/src/hotspot/cpu/s390/interp_masm_s390.cpp +++ b/src/hotspot/cpu/s390/interp_masm_s390.cpp @@ -1012,7 +1012,7 @@ void InterpreterMacroAssembler::lock_object(Register monitor, Register object) { } if (LockingMode == LM_LIGHTWEIGHT) { - lightweight_lock(object, header, tmp, slow_case); + lightweight_lock(monitor, object, header, tmp, slow_case); } else if (LockingMode == LM_LEGACY) { // Load markWord from object into header. diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.cpp b/src/hotspot/cpu/s390/macroAssembler_s390.cpp index 65a7d3abe90af..6c26e17d5ce3b 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.cpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.cpp @@ -6007,10 +6007,10 @@ SkipIfEqual::~SkipIfEqual() { // - obj: the object to be locked, contents preserved. // - temp1, temp2: temporary registers, contents destroyed. // Note: make sure Z_R1 is not manipulated here when C2 compiler is in play -void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register temp2, Label& slow) { +void MacroAssembler::lightweight_lock(Register basic_lock, Register obj, Register temp1, Register temp2, Label& slow) { assert(LockingMode == LM_LIGHTWEIGHT, "only used with new lightweight locking"); - assert_different_registers(obj, temp1, temp2); + assert_different_registers(basic_lock, obj, temp1, temp2); Label push; const Register top = temp1; @@ -6022,6 +6022,11 @@ void MacroAssembler::lightweight_lock(Register obj, Register temp1, Register tem // instruction emitted as it is part of C1's null check semantics. z_lg(mark, Address(obj, mark_offset)); + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + const Address om_cache_addr = Address(basic_lock, BasicObjectLock::lock_offset() + in_ByteSize((BasicLock::object_monitor_cache_offset_in_bytes()))); + z_mvghi(om_cache_addr, 0); + } // First we need to check if the lock-stack has room for pushing the object reference. z_lgf(top, Address(Z_thread, ls_top_offset)); @@ -6145,8 +6150,8 @@ void MacroAssembler::lightweight_unlock(Register obj, Register temp1, Register t bind(unlocked); } -void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2) { - assert_different_registers(obj, tmp1, tmp2); +void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) { + assert_different_registers(obj, box, tmp1, tmp2); // Handle inflated monitor. NearLabel inflated; @@ -6155,6 +6160,11 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe // Finish fast lock unsuccessfully. MUST branch to with flag == EQ NearLabel slow_path; + if (UseObjectMonitorTable) { + // Clear cache in case fast locking succeeds. + z_mvghi(Address(box, BasicLock::object_monitor_cache_offset_in_bytes()), 0); + } + if (DiagnoseSyncOnValueBasedClasses != 0) { load_klass(tmp1, obj); z_tm(Address(tmp1, Klass::misc_flags_offset()), KlassFlags::_misc_is_value_based_class); @@ -6219,33 +6229,77 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe { // Handle inflated monitor. bind(inflated); + const Register tmp1_monitor = tmp1; if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register tagged_monitor = mark; - const Register zero = tmp2; - - // Try to CAS m->owner from null to current thread. - // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. - // Otherwise, register zero is filled with the current owner. - z_lghi(zero, 0); - z_csg(zero, Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), tagged_monitor); - z_bre(locked); - - // Check if recursive. - z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction - z_brne(slow_path); - - // Recursive - z_agsi(Address(tagged_monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), 1ll); - z_cgr(zero, zero); - // z_bru(locked); - // Uncomment above line in the future, for now jump address is right next to us. + assert(tmp1_monitor == mark, "should be the same here"); } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - z_ltgr(obj, obj); + NearLabel monitor_found; + + // load cache address + z_la(tmp1, Address(Z_thread, JavaThread::om_cache_oops_offset())); + + const int num_unrolled = 2; + for (int i = 0; i < num_unrolled; i++) { + z_cg(obj, Address(tmp1)); + z_bre(monitor_found); + add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference())); + } + + NearLabel loop; + // Search for obj in cache + + bind(loop); + + // check for match. + z_cg(obj, Address(tmp1)); + z_bre(monitor_found); + + // search until null encountered, guaranteed _null_sentinel at end. + add2reg(tmp1, in_bytes(OMCache::oop_to_oop_difference())); + z_cghsi(0, tmp1, 0); + z_brne(loop); // if not EQ to 0, go for another loop + + // we reached to the end, cache miss + z_ltgr(obj, obj); // set CC to NE z_bru(slow_path); + + // cache hit + bind(monitor_found); + z_lg(tmp1_monitor, Address(tmp1, OMCache::oop_to_monitor_difference())); } + NearLabel monitor_locked; + // lock the monitor + + // mark contains the tagged ObjectMonitor*. + const Register tagged_monitor = mark; + const Register zero = tmp2; + + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address owner_address(tmp1_monitor, ObjectMonitor::owner_offset() - monitor_tag); + const Address recursions_address(tmp1_monitor, ObjectMonitor::recursions_offset() - monitor_tag); + + + // Try to CAS m->owner from null to current thread. + // If m->owner is null, then csg succeeds and sets m->owner=THREAD and CR=EQ. + // Otherwise, register zero is filled with the current owner. + z_lghi(zero, 0); + z_csg(zero, Z_thread, owner_address); + z_bre(monitor_locked); + + // Check if recursive. + z_cgr(Z_thread, zero); // zero contains the owner from z_csg instruction + z_brne(slow_path); + + // Recursive + z_agsi(recursions_address, 1ll); + + bind(monitor_locked); + if (UseObjectMonitorTable) { + // Cache the monitor for unlock + z_stg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + } + // set the CC now + z_cgr(obj, obj); } BLOCK_COMMENT("} handle_inflated_monitor_lightweight_locking"); @@ -6270,11 +6324,11 @@ void MacroAssembler::compiler_fast_lock_lightweight_object(Register obj, Registe // C2 uses the value of flag (NE vs EQ) to determine the continuation. } -void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2) { - assert_different_registers(obj, tmp1, tmp2); +void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2) { + assert_different_registers(obj, box, tmp1, tmp2); // Handle inflated monitor. - NearLabel inflated, inflated_load_monitor; + NearLabel inflated, inflated_load_mark; // Finish fast unlock successfully. MUST reach to with flag == EQ. NearLabel unlocked; // Finish fast unlock unsuccessfully. MUST branch to with flag == NE. @@ -6294,7 +6348,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis z_aghi(top, -oopSize); z_cg(obj, Address(Z_thread, top)); - branch_optimized(bcondNotEqual, inflated_load_monitor); + branch_optimized(bcondNotEqual, inflated_load_mark); // Pop lock-stack. #ifdef ASSERT @@ -6315,6 +6369,9 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis // Not recursive // Check for monitor (0b10). + // Because we got here by popping (meaning we pushed in locked) + // there will be no monitor in the box. So we need to push back the obj + // so that the runtime can fix any potential anonymous owner. z_lg(mark, Address(obj, mark_offset)); z_tmll(mark, markWord::monitor_value); if (!UseObjectMonitorTable) { @@ -6353,7 +6410,7 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis { // Handle inflated monitor. - bind(inflated_load_monitor); + bind(inflated_load_mark); z_lg(mark, Address(obj, mark_offset)); @@ -6378,49 +6435,61 @@ void MacroAssembler::compiler_fast_unlock_lightweight_object(Register obj, Regis bind(check_done); #endif // ASSERT + const Register tmp1_monitor = tmp1; + if (!UseObjectMonitorTable) { - // mark contains the tagged ObjectMonitor*. - const Register monitor = mark; + assert(tmp1_monitor == mark, "should be the same here"); + } else { + // Uses ObjectMonitorTable. Look for the monitor in our BasicLock on the stack. + z_lg(tmp1_monitor, Address(box, BasicLock::object_monitor_cache_offset_in_bytes())); + // null check with ZF == 0, no valid pointer below alignof(ObjectMonitor*) + z_cghi(tmp1_monitor, alignof(ObjectMonitor*)); - NearLabel not_recursive; - const Register recursions = tmp2; + z_brl(slow_path); + } - // Check if recursive. - load_and_test_long(recursions, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions))); - z_bre(not_recursive); // if 0 then jump, it's not recursive locking + // mark contains the tagged ObjectMonitor*. + const Register monitor = mark; - // Recursive unlock - z_agsi(Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(recursions)), -1ll); - z_cgr(monitor, monitor); // set the CC to EQUAL - z_bru(unlocked); + const ByteSize monitor_tag = in_ByteSize(UseObjectMonitorTable ? 0 : checked_cast(markWord::monitor_value)); + const Address recursions_address{monitor, ObjectMonitor::recursions_offset() - monitor_tag}; + const Address cxq_address{monitor, ObjectMonitor::cxq_offset() - monitor_tag}; + const Address EntryList_address{monitor, ObjectMonitor::EntryList_offset() - monitor_tag}; + const Address owner_address{monitor, ObjectMonitor::owner_offset() - monitor_tag}; - bind(not_recursive); + NearLabel not_recursive; + const Register recursions = tmp2; - NearLabel not_ok; - // Check if the entry lists are empty. - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(EntryList))); - z_brne(not_ok); - load_and_test_long(tmp2, Address(monitor, OM_OFFSET_NO_MONITOR_VALUE_TAG(cxq))); - z_brne(not_ok); + // Check if recursive. + load_and_test_long(recursions, recursions_address); + z_bre(not_recursive); // if 0 then jump, it's not recursive locking - z_release(); - z_stg(tmp2 /*=0*/, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); + // Recursive unlock + z_agsi(recursions_address, -1ll); + z_cgr(monitor, monitor); // set the CC to EQUAL + z_bru(unlocked); - z_bru(unlocked); // CC = EQ here + bind(not_recursive); - bind(not_ok); + NearLabel not_ok; + // Check if the entry lists are empty. + load_and_test_long(tmp2, EntryList_address); + z_brne(not_ok); + load_and_test_long(tmp2, cxq_address); + z_brne(not_ok); - // The owner may be anonymous, and we removed the last obj entry in - // the lock-stack. This loses the information about the owner. - // Write the thread to the owner field so the runtime knows the owner. - z_stg(Z_thread, OM_OFFSET_NO_MONITOR_VALUE_TAG(owner), monitor); - z_bru(slow_path); // CC = NE here - } else { - // OMCache lookup not supported yet. Take the slowpath. - // Set flag to NE - z_ltgr(obj, obj); - z_bru(slow_path); - } + z_release(); + z_stg(tmp2 /*=0*/, owner_address); + + z_bru(unlocked); // CC = EQ here + + bind(not_ok); + + // The owner may be anonymous, and we removed the last obj entry in + // the lock-stack. This loses the information about the owner. + // Write the thread to the owner field so the runtime knows the owner. + z_stg(Z_thread, owner_address); + z_bru(slow_path); // CC = NE here } bind(unlocked); diff --git a/src/hotspot/cpu/s390/macroAssembler_s390.hpp b/src/hotspot/cpu/s390/macroAssembler_s390.hpp index c380f4dec1029..5d3a4c2994091 100644 --- a/src/hotspot/cpu/s390/macroAssembler_s390.hpp +++ b/src/hotspot/cpu/s390/macroAssembler_s390.hpp @@ -752,10 +752,10 @@ class MacroAssembler: public Assembler { void compiler_fast_lock_object(Register oop, Register box, Register temp1, Register temp2); void compiler_fast_unlock_object(Register oop, Register box, Register temp1, Register temp2); - void lightweight_lock(Register obj, Register tmp1, Register tmp2, Label& slow); + void lightweight_lock(Register basic_lock, Register obj, Register tmp1, Register tmp2, Label& slow); void lightweight_unlock(Register obj, Register tmp1, Register tmp2, Label& slow); - void compiler_fast_lock_lightweight_object(Register obj, Register tmp1, Register tmp2); - void compiler_fast_unlock_lightweight_object(Register obj, Register tmp1, Register tmp2); + void compiler_fast_lock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2); + void compiler_fast_unlock_lightweight_object(Register obj, Register box, Register tmp1, Register tmp2); void resolve_jobject(Register value, Register tmp1, Register tmp2); void resolve_global_jobject(Register value, Register tmp1, Register tmp2); diff --git a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp index 9954c78ce1efa..468610b588e91 100644 --- a/src/hotspot/cpu/s390/sharedRuntime_s390.cpp +++ b/src/hotspot/cpu/s390/sharedRuntime_s390.cpp @@ -43,6 +43,7 @@ #include "runtime/sharedRuntime.hpp" #include "runtime/signature.hpp" #include "runtime/stubRoutines.hpp" +#include "runtime/timerTrace.hpp" #include "runtime/vframeArray.hpp" #include "utilities/align.hpp" #include "utilities/macros.hpp" @@ -1713,7 +1714,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for locking. if (LockingMode == LM_LIGHTWEIGHT) { // Fast_lock kills r_temp_1, r_temp_2. - __ compiler_fast_lock_lightweight_object(r_oop, r_tmp1, r_tmp2); + __ compiler_fast_lock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2); } else { // Fast_lock kills r_temp_1, r_temp_2. __ compiler_fast_lock_object(r_oop, r_box, r_tmp1, r_tmp2); @@ -1917,7 +1918,7 @@ nmethod *SharedRuntime::generate_native_wrapper(MacroAssembler *masm, // Try fastpath for unlocking. if (LockingMode == LM_LIGHTWEIGHT) { // Fast_unlock kills r_tmp1, r_tmp2. - __ compiler_fast_unlock_lightweight_object(r_oop, r_tmp1, r_tmp2); + __ compiler_fast_unlock_lightweight_object(r_oop, r_box, r_tmp1, r_tmp2); } else { // Fast_unlock kills r_tmp1, r_tmp2. __ compiler_fast_unlock_object(r_oop, r_box, r_tmp1, r_tmp2); diff --git a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp index c16e444904563..2c2e8ed9e3b3a 100644 --- a/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp +++ b/src/hotspot/cpu/s390/templateInterpreterGenerator_s390.cpp @@ -1224,6 +1224,7 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M case Interpreter::java_lang_math_sin : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsin); break; case Interpreter::java_lang_math_cos : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dcos); break; case Interpreter::java_lang_math_tan : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dtan); break; + case Interpreter::java_lang_math_tanh : /* run interpreted */ break; case Interpreter::java_lang_math_abs : /* run interpreted */ break; case Interpreter::java_lang_math_sqrt : /* runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dsqrt); not available */ break; case Interpreter::java_lang_math_log : runtime_entry = CAST_FROM_FN_PTR(address, SharedRuntime::dlog); break; diff --git a/src/hotspot/cpu/x86/assembler_x86.cpp b/src/hotspot/cpu/x86/assembler_x86.cpp index 352cfc0018848..07476ab342f6d 100644 --- a/src/hotspot/cpu/x86/assembler_x86.cpp +++ b/src/hotspot/cpu/x86/assembler_x86.cpp @@ -8048,6 +8048,14 @@ void Assembler::andpd(XMMRegister dst, XMMRegister src) { emit_int16(0x54, (0xC0 | encode)); } +void Assembler::andnpd(XMMRegister dst, XMMRegister src) { + NOT_LP64(assert(VM_Version::supports_sse2(), "")); + InstructionAttr attributes(AVX_128bit, /* rex_w */ !_legacy_mode_dq, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true); + attributes.set_rex_vex_w_reverted(); + int encode = simd_prefix_and_encode(dst, dst, src, VEX_SIMD_66, VEX_OPCODE_0F, &attributes); + emit_int16(0x55, (0xC0 | encode)); +} + void Assembler::andps(XMMRegister dst, XMMRegister src) { NOT_LP64(assert(VM_Version::supports_sse(), "")); InstructionAttr attributes(AVX_128bit, /* rex_w */ false, /* legacy_mode */ _legacy_mode_dq, /* no_mask_reg */ true, /* uses_vl */ true); diff --git a/src/hotspot/cpu/x86/assembler_x86.hpp b/src/hotspot/cpu/x86/assembler_x86.hpp index 7f4790e05665e..62700d1fa1bd5 100644 --- a/src/hotspot/cpu/x86/assembler_x86.hpp +++ b/src/hotspot/cpu/x86/assembler_x86.hpp @@ -2631,6 +2631,7 @@ class Assembler : public AbstractAssembler { // Bitwise Logical AND of Packed Floating-Point Values void andpd(XMMRegister dst, XMMRegister src); + void andnpd(XMMRegister dst, XMMRegister src); void andps(XMMRegister dst, XMMRegister src); void vandpd(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); void vandps(XMMRegister dst, XMMRegister nds, XMMRegister src, int vector_len); diff --git a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp index ff237d16d2216..36e2021138f2e 100644 --- a/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp +++ b/src/hotspot/cpu/x86/c1_LIRGenerator_x86.cpp @@ -807,7 +807,11 @@ void LIRGenerator::do_MathIntrinsic(Intrinsic* x) { if (x->id() == vmIntrinsics::_dexp || x->id() == vmIntrinsics::_dlog || x->id() == vmIntrinsics::_dpow || x->id() == vmIntrinsics::_dcos || x->id() == vmIntrinsics::_dsin || x->id() == vmIntrinsics::_dtan || - x->id() == vmIntrinsics::_dlog10) { + x->id() == vmIntrinsics::_dlog10 +#ifdef _LP64 + || x->id() == vmIntrinsics::_dtanh +#endif + ) { do_LibmIntrinsic(x); return; } @@ -989,11 +993,17 @@ void LIRGenerator::do_LibmIntrinsic(Intrinsic* x) { break; case vmIntrinsics::_dtan: if (StubRoutines::dtan() != nullptr) { - __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args()); + __ call_runtime_leaf(StubRoutines::dtan(), getThreadTemp(), result_reg, cc->args()); } else { __ call_runtime_leaf(CAST_FROM_FN_PTR(address, SharedRuntime::dtan), getThreadTemp(), result_reg, cc->args()); } break; + case vmIntrinsics::_dtanh: + assert(StubRoutines::dtanh() != nullptr, "tanh intrinsic not found"); + if (StubRoutines::dtanh() != nullptr) { + __ call_runtime_leaf(StubRoutines::dtanh(), getThreadTemp(), result_reg, cc->args()); + } + break; default: ShouldNotReachHere(); } #endif // _LP64 diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp index f5f0d6c884198..65d7c1e3303ba 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.cpp @@ -636,7 +636,7 @@ void ZBarrierSetAssembler::copy_load_at(MacroAssembler* masm, // Remove metadata bits so that the store side (vectorized or non-vectorized) can // inject the store-good color with an or instruction. - __ andq(dst, _zpointer_address_mask); + __ andq(dst, ZPointerAddressMask); if ((decorators & ARRAYCOPY_CHECKCAST) != 0) { // The checkcast arraycopy needs to be able to dereference the oops in order to perform a typechecks. diff --git a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp index 7c3716ba0da9f..5fbc7ea1be16e 100644 --- a/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp +++ b/src/hotspot/cpu/x86/gc/z/zBarrierSetAssembler_x86.hpp @@ -64,7 +64,7 @@ class ZBarrierSetAssembler : public ZBarrierSetAssemblerBase { GrowableArrayCHeap _store_good_relocations; public: - static const int32_t _zpointer_address_mask = 0xFFFF0000; + static const int32_t ZPointerAddressMask = 0xFFFF0000; ZBarrierSetAssembler(); diff --git a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad index 30220c0629e5e..455d622acdf17 100644 --- a/src/hotspot/cpu/x86/gc/z/z_x86_64.ad +++ b/src/hotspot/cpu/x86/gc/z/z_x86_64.ad @@ -141,7 +141,7 @@ instruct zLoadPNullCheck(rFlagsReg cr, memory op, immP0 zero) ins_encode %{ // A null pointer will have all address bits 0. This mask sign extends // all address bits, so we can test if the address is 0. - __ testq($op$$Address, ZBarrierSetAssembler::_zpointer_address_mask); + __ testq($op$$Address, ZBarrierSetAssembler::ZPointerAddressMask); %} ins_pipe(ialu_cr_reg_imm); %} diff --git a/src/hotspot/cpu/x86/macroAssembler_x86.cpp b/src/hotspot/cpu/x86/macroAssembler_x86.cpp index d634c1e575799..893ae4e844ba4 100644 --- a/src/hotspot/cpu/x86/macroAssembler_x86.cpp +++ b/src/hotspot/cpu/x86/macroAssembler_x86.cpp @@ -5756,7 +5756,7 @@ void MacroAssembler::verify_heapbase(const char* msg) { assert (Universe::heap() != nullptr, "java heap should be initialized"); if (CheckCompressedOops) { Label ok; - ExternalAddress src2(CompressedOops::ptrs_base_addr()); + ExternalAddress src2(CompressedOops::base_addr()); const bool is_src2_reachable = reachable(src2); if (!is_src2_reachable) { push(rscratch1); // cmpptr trashes rscratch1 @@ -6047,10 +6047,10 @@ void MacroAssembler::reinit_heapbase() { if (CompressedOops::base() == nullptr) { MacroAssembler::xorptr(r12_heapbase, r12_heapbase); } else { - mov64(r12_heapbase, (int64_t)CompressedOops::ptrs_base()); + mov64(r12_heapbase, (int64_t)CompressedOops::base()); } } else { - movptr(r12_heapbase, ExternalAddress(CompressedOops::ptrs_base_addr())); + movptr(r12_heapbase, ExternalAddress(CompressedOops::base_addr())); } } } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp index 2bc4a0a9cba94..4f37dc31d0305 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.cpp @@ -3573,6 +3573,9 @@ void StubGenerator::generate_libm_stubs() { if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtan)) { StubRoutines::_dtan = generate_libmTan(); // from stubGenerator_x86_64_tan.cpp } + if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dtanh)) { + StubRoutines::_dtanh = generate_libmTanh(); // from stubGenerator_x86_64_tanh.cpp + } if (vmIntrinsics::is_intrinsic_available(vmIntrinsics::_dexp)) { StubRoutines::_dexp = generate_libmExp(); // from stubGenerator_x86_64_exp.cpp } diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp index d65c681585d6d..0a81da4f7c957 100644 --- a/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64.hpp @@ -546,6 +546,7 @@ class StubGenerator: public StubCodeGenerator { address generate_libmSin(); address generate_libmCos(); address generate_libmTan(); + address generate_libmTanh(); address generate_libmExp(); address generate_libmPow(); address generate_libmLog(); diff --git a/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp new file mode 100644 index 0000000000000..92ac78e15cba9 --- /dev/null +++ b/src/hotspot/cpu/x86/stubGenerator_x86_64_tanh.cpp @@ -0,0 +1,502 @@ +/* +* Copyright (c) 2024, Intel Corporation. All rights reserved. +* Intel Math Library (LIBM) Source Code +* +* 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. +* +*/ + +#include "precompiled.hpp" +#include "macroAssembler_x86.hpp" +#include "stubGenerator_x86_64.hpp" + +/******************************************************************************/ +// ALGORITHM DESCRIPTION +// --------------------- +// +// tanh(x)=(exp(x)-exp(-x))/(exp(x)+exp(-x))=(1-exp(-2*x))/(1+exp(-2*x)) +// +// Let |x|=xH+xL (upper 26 bits, lower 27 bits) +// log2(e) rounded to 26 bits (high part) plus a double precision low part is +// L2EH+L2EL (upper 26, lower 53 bits) +// +// Let xH*L2EH=k+f+r`, where (k+f)*2^8*2=int(xH*L2EH*2^9), +// f=0.b1 b2 ... b8, k integer +// 2^{-f} is approximated as Tn[f]+Dn[f] +// Tn stores the high 53 bits, Dn stores (2^{-f}-Tn[f]) rounded to double precision +// +// r=r`+xL*L2EH+|x|*L2EL, |r|<2^{-9}+2^{-14}, +// for |x| in [23/64,3*2^7) +// e^{-2*|x|}=2^{-k-f}*2^{-r} ~ 2^{-k}*(Tn+Dn)*(1+p)=(T0+D0)*(1+p) +// +// For |x| in [2^{-4},2^5): +// 2^{-r}-1 ~ p=c1*r+c2*r^2+..+c5*r^5 +// Let R=1/(1+T0+p*T0), truncated to 35 significant bits +// R=1/(1+T0+D0+p*(T0+D0))*(1+eps), |eps|<2^{-33} +// 1+T0+D0+p*(T0+D0)=KH+KL, where +// KH=(1+T0+c1*r*T0)_high (leading 17 bits) +// KL=T0_low+D0+(c1*r*T0)_low+c1*r*D0+(c2*r^2+..c5*r^5)*T0 +// eps ~ (R*KH-1)+R*KL +// 1/(1+T0+D0+p*(T0+D0)) ~ R-R*eps +// The result is approximated as (1-T0-D0-(T0+D0)*p)*(R-R*eps) +// 1-T0-D0-(T0+D0)*p=-((KH-2)+KL) +// The result is formed as +// (KH-2)*R+(-(KH-2)*R*eps+(KL*R-KL*R*eps)), with the correct sign +// set at the end +// +// For |x| in [2^{-64},2^{-4}): +// A Taylor series expansion is used (x+p3*x^3+..+p13*x^{13}) +// +// For |x|<2^{-64}: x is returned +// +// For |x|>=2^32: return +/-1 +// +// Special cases: +// tanh(NaN) = quiet NaN, and raise invalid exception +// tanh(INF) = that INF +// tanh(+/-0) = +/-0 +// +/******************************************************************************/ + +ATTRIBUTE_ALIGNED(4) static const juint _HALFMASK[] = +{ + 4160749568, 2147483647 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _ONEMASK[] = +{ + 0, 1072693248 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _TWOMASK[] = +{ + 0, 1073741824 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _MASK3[] = +{ + 0, 4294967280, 0, 4294967280 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _RMASK[] = +{ + 4294705152, 4294967295, 4294705152, 4294967295 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _L2E[] = +{ + 1610612736, 1082594631, 4166901572, 1055174155 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _Shifter[] = +{ + 0, 1127743488, 0, 3275227136 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _cv[] = +{ + 3884607281, 3168131199, 3607404735, 3190582024, 1874480759, + 1032041131, 4286760334, 1053736893, 4277811695, 3211144770, + 0, 0 +}; + +ATTRIBUTE_ALIGNED(4) static const juint _pv[] = +{ + 236289503, 1064135997, 463583772, 3215696314, 1441186365, + 3212977891, 286331153, 1069617425, 2284589306, 1066820852, + 1431655765, 3218429269 +}; + +ATTRIBUTE_ALIGNED(16) static const juint _T2_neg_f[] = +{ + 0, 1072693248, 0, 0, 1797923801, 1072687577, + 1950547427, 1013229059, 730821105, 1072681922, 2523232743, 1012067188, + 915592468, 1072676282, 352947894, 3161024371, 2174652632, 1072670657, + 4087714590, 1014450259, 35929225, 1072665048, 2809788041, 3159436968, + 2912730644, 1072659453, 3490067722, 3163405074, 2038973688, 1072653874, + 892941374, 1016046459, 1533953344, 1072648310, 769171851, 1015665633, + 1222472308, 1072642761, 1054357470, 3161021018, 929806999, 1072637227, + 3205336643, 1015259557, 481706282, 1072631708, 1696079173, 3162710528, + 3999357479, 1072626203, 2258941616, 1015924724, 2719515920, 1072620714, + 2760332941, 1015137933, 764307441, 1072615240, 3021057420, 3163329523, + 2256325230, 1072609780, 580117746, 1015317295, 2728693978, 1072604335, + 396109971, 3163462691, 2009970496, 1072598905, 2159039665, 3162572948, + 4224142467, 1072593489, 3389820386, 1015207202, 610758006, 1072588089, + 1965209397, 3161866232, 3884662774, 1072582702, 2158611599, 1014210185, + 991358482, 1072577331, 838715019, 3163157668, 351641897, 1072571974, + 2172261526, 3163010599, 1796832535, 1072566631, 3176955716, 3160585513, + 863738719, 1072561303, 1326992220, 3162613197, 1679558232, 1072555989, + 2390342287, 3163333970, 4076975200, 1072550689, 2029000899, 1015208535, + 3594158869, 1072545404, 2456521700, 3163256561, 64696965, 1072540134, + 1768797490, 1015816960, 1912561781, 1072534877, 3147495102, 1015678253, + 382305176, 1072529635, 2347622376, 3162578625, 3898795731, 1072524406, + 1249994144, 1011869818, 3707479175, 1072519192, 3613079303, 1014164738, + 3939148246, 1072513992, 3210352148, 1015274323, 135105010, 1072508807, + 1906148728, 3163375739, 721996136, 1072503635, 563754734, 1015371318, + 1242007932, 1072498477, 1132034716, 3163339831, 1532734324, 1072493333, + 3094216535, 3163162857, 1432208378, 1072488203, 1401068914, 3162363963, + 778901109, 1072483087, 2248183955, 3161268751, 3706687593, 1072477984, + 3521726940, 1013253067, 1464976603, 1072472896, 3507292405, 3161977534, + 2483480501, 1072467821, 1216371780, 1013034172, 2307442995, 1072462760, + 3190117721, 3162404539, 777507147, 1072457713, 4282924205, 1015187533, + 2029714210, 1072452679, 613660079, 1015099143, 1610600570, 1072447659, + 3766732298, 1015760183, 3657065772, 1072442652, 399025623, 3162957078, + 3716502172, 1072437659, 2303740125, 1014042725, 1631695677, 1072432680, + 2717633076, 3162344026, 1540824585, 1072427714, 1064017011, 3163487690, + 3287523847, 1072422761, 1625971539, 3157009955, 2420883922, 1072417822, + 2049810052, 1014119888, 3080351519, 1072412896, 3379126788, 3157218001, + 815859274, 1072407984, 240396590, 3163487443, 4062661092, 1072403084, + 1422616006, 3163255318, 4076559943, 1072398198, 2119478331, 3160758351, + 703710506, 1072393326, 1384660846, 1015195891, 2380618042, 1072388466, + 3149557219, 3163320799, 364333489, 1072383620, 3923737744, 3161421373, + 3092190715, 1072378786, 814012168, 3159523422, 1822067026, 1072373966, + 1241994956, 1015340290, 697153126, 1072369159, 1283515429, 3163283189, + 3861050111, 1072364364, 254893773, 3162813180, 2572866477, 1072359583, + 878562433, 1015521741, 977020788, 1072354815, 3065100517, 1015541563, + 3218338682, 1072350059, 3404164304, 3162477108, 557149882, 1072345317, + 3672720709, 1014537265, 1434058175, 1072340587, 251133233, 1015085769, + 1405169241, 1072335870, 2998539689, 3162830951, 321958744, 1072331166, + 3401933767, 1015794558, 2331271250, 1072326474, 812057446, 1012207446, + 2990417245, 1072321795, 3683467745, 3163369326, 2152073944, 1072317129, + 1486860576, 3163203456, 3964284211, 1072312475, 2111583915, 1015427164, + 3985553595, 1072307834, 4002146062, 1015834136, 2069751141, 1072303206, + 1562170675, 3162724681, 2366108318, 1072298590, 2867985102, 3161762254, + 434316067, 1072293987, 2028358766, 1013458122, 424392917, 1072289396, + 2749202995, 3162838718, 2191782032, 1072284817, 2960257726, 1013742662, + 1297350157, 1072280251, 1308022040, 3163412558, 1892288442, 1072275697, + 2446255666, 3162600381, 3833209506, 1072271155, 2722920684, 1013754842, + 2682146384, 1072266626, 2082178513, 3163363419, 2591453363, 1072262109, + 2132396182, 3159074198, 3418903055, 1072257604, 2527457337, 3160820604, + 727685349, 1072253112, 2038246809, 3162358742, 2966275557, 1072248631, + 2176155324, 3159842759, 1403662306, 1072244163, 2788809599, 3161671007, + 194117574, 1072239707, 777528612, 3163412089, 3492293770, 1072235262, + 2248032210, 1015386826, 2568320822, 1072230830, 2732824428, 1014352915, + 1577608921, 1072226410, 1875489510, 3162968394, 380978316, 1072222002, + 854188970, 3160462686, 3134592888, 1072217605, 4232266862, 1015991134, + 1110089947, 1072213221, 1451641639, 1015474673, 2759350287, 1072208848, + 1148526634, 1015894933, 3649726105, 1072204487, 4085036346, 1015649474, + 3643909174, 1072200138, 3537586109, 1014354647, 2604962541, 1072195801, + 2614425274, 3163539192, 396319521, 1072191476, 4172420816, 3159074632, + 1176749997, 1072187162, 2738998779, 3162035844, 515457527, 1072182860, + 836709333, 1015651226, 2571947539, 1072178569, 3558159064, 3163376669, + 2916157145, 1072174290, 219487565, 1015309367, 1413356050, 1072170023, + 1651349291, 3162668166, 2224145553, 1072165767, 3482522030, 3161489169, + 919555682, 1072161523, 3121969534, 1012948226, 1660913392, 1072157290, + 4218599604, 1015135707, 19972402, 1072153069, 3507899862, 1016009292, + 158781403, 1072148859, 2221464712, 3163286453, 1944781191, 1072144660, + 3993278767, 3161724279, 950803702, 1072140473, 1655364926, 1015237032, + 1339972927, 1072136297, 167908909, 1015572152, 2980802057, 1072132132, + 378619896, 1015773303, 1447192521, 1072127979, 1462857171, 3162514521, + 903334909, 1072123837, 1636462108, 1015039997, 1218806132, 1072119706, + 1818613052, 3162548441, 2263535754, 1072115586, 752233586, 3162639008, + 3907805044, 1072111477, 2257091225, 3161550407, 1727278727, 1072107380, + 3562710623, 1011471940, 4182873220, 1072103293, 629542646, 3161996303, + 2555984613, 1072099218, 2652555442, 3162552692, 1013258799, 1072095154, + 1748797611, 3160129082, 3721688645, 1072091100, 3069276937, 1015839401, + 1963711167, 1072087058, 1744767757, 3160574294, 4201977662, 1072083026, + 748330254, 1013594357, 1719614413, 1072079006, 330458198, 3163282740, + 2979960120, 1072074996, 2599109725, 1014498493, 3561793907, 1072070997, + 1157054053, 1011890350, 3339203574, 1072067009, 1483497780, 3162408754, + 2186617381, 1072063032, 2270764084, 3163272713, 4273770423, 1072059065, + 3383180809, 3163218901, 885834528, 1072055110, 1973258547, 3162261564, + 488188413, 1072051165, 3199821029, 1015564048, 2956612997, 1072047230, + 2118169751, 3162735553, 3872257780, 1072043306, 1253592103, 1015958334, + 3111574537, 1072039393, 2606161479, 3162759746, 551349105, 1072035491, + 3821916050, 3162106589, 363667784, 1072031599, 813753950, 1015785209, + 2425981843, 1072027717, 2830390851, 3163346599, 2321106615, 1072023846, + 2171176610, 1009535771, 4222122499, 1072019985, 1277378074, 3163256737, + 3712504873, 1072016135, 88491949, 1015427660, 671025100, 1072012296, + 3832014351, 3163022030, 3566716925, 1072008466, 1536826856, 1014142433, + 3689071823, 1072004647, 2321004996, 3162552716, 917841882, 1072000839, + 18715565, 1015659308, 3723038930, 1071997040, 378465264, 3162569582, + 3395129871, 1071993252, 4025345435, 3162335388, 4109806887, 1071989474, + 422403966, 1014469229, 1453150082, 1071985707, 498154669, 3161488062, + 3896463087, 1071981949, 1139797873, 3161233805, 2731501122, 1071978202, + 1774031855, 3162470021, 2135241198, 1071974465, 1236747871, 1013589147, + 1990012071, 1071970738, 3529070563, 3162813193, 2178460671, 1071967021, + 777878098, 3162842493, 2583551245, 1071963314, 3161094195, 1015606491, + 3088564500, 1071959617, 1762311517, 1015045673, 3577096743, 1071955930, + 2951496418, 1013793687, 3933059031, 1071952253, 2133366768, 3161531832, + 4040676318, 1071948586, 4090609238, 1015663458, 3784486610, 1071944929, + 1581883040, 3161698953, 3049340112, 1071941282, 3062915824, 1013170595, + 1720398391, 1071937645, 3980678963, 3163300080, 3978100823, 1071934017, + 3513027190, 1015845963, 1118294578, 1071930400, 2197495694, 3159909401, + 1617004845, 1071926792, 82804944, 1010342778, 1065662932, 1071923194, + 2533670915, 1014530238, 3645941911, 1071919605, 3814685081, 3161573341, + 654919306, 1071916027, 3232961757, 3163047469, 569847338, 1071912458, + 472945272, 3159290729, 3278348324, 1071908898, 3069497416, 1014750712, + 78413852, 1071905349, 4183226867, 3163017251, 3743175029, 1071901808, + 2072812490, 3162175075, 1276261410, 1071898278, 300981948, 1014684169, + 1156440435, 1071894757, 2351451249, 1013967056, 3272845541, 1071891245, + 928852419, 3163488248, 3219942644, 1071887743, 3798990616, 1015368806, + 887463927, 1071884251, 3596744163, 3160794166, 460407023, 1071880768, + 4237175092, 3163138469, 1829099622, 1071877294, 1016661181, 3163461005, + 589198666, 1071873830, 2664346172, 3163157962, 926591435, 1071870375, + 3208833762, 3162913514, 2732492859, 1071866929, 2691479646, 3162255684, + 1603444721, 1071863493, 1548633640, 3162201326, 1726216749, 1071860066, + 2466808228, 3161676405, 2992903935, 1071856648, 2218154406, 1015228193, + 1000925746, 1071853240, 1018491672, 3163309544, 4232894513, 1071849840, + 2383938684, 1014668519, 3991843581, 1071846450, 4092853457, 1014585763, + 171030293, 1071843070, 3526460132, 1014428778, 1253935211, 1071839698, + 1395382931, 3159702613, 2839424854, 1071836335, 1171596163, 1013041679, + 526652809, 1071832982, 4223459736, 1015879375, 2799960843, 1071829637, + 1423655381, 1015022151, 964107055, 1071826302, 2800439588, 3162833221, + 3504003472, 1071822975, 3594001060, 3157330652, 1724976915, 1071819658, + 420909223, 3163117379, 4112506593, 1071816349, 2947355221, 1014371048, + 1972484976, 1071813050, 675290301, 3161640050, 3790955393, 1071809759, + 2352942462, 3163180090, 874372905, 1071806478, 100263788, 1015940732, + 1709341917, 1071803205, 2571168217, 1014152499, 1897844341, 1071799941, + 1254300460, 1015275938, 1337108031, 1071796686, 3203724452, 1014677845, + 4219606026, 1071793439, 2434574742, 1014681548, 1853186616, 1071790202, + 3066496371, 1015656574, 2725843665, 1071786973, 1433917087, 1014838523, + 2440944790, 1071783753, 2492769774, 1014147454, 897099801, 1071780542, + 754756297, 1015241005, 2288159958, 1071777339, 2169144469, 1014876021, + 2218315341, 1071774145, 2694295388, 3163288868, 586995997, 1071770960, + 41662348, 3162627992, 1588871207, 1071767783, 143439582, 3162963416, + 828946858, 1071764615, 10642492, 1015939438, 2502433899, 1071761455, + 2148595913, 1015023991, 2214878420, 1071758304, 892270087, 3163116422, + 4162030108, 1071755161, 2763428480, 1015529349, 3949972341, 1071752027, + 2068408548, 1014913868, 1480023343, 1071748902, 2247196168, 1015327453, + 948735466, 1071745785, 3516338028, 3162574883, 2257959872, 1071742676, + 3802946148, 1012964927, 1014845819, 1071739576, 3117910646, 3161559105, + 1416741826, 1071736484, 2196380210, 1011413563, 3366293073, 1071733400, + 3119426314, 1014120554, 2471440686, 1071730325, 968836267, 3162214888, + 2930322912, 1071727258, 2599499422, 3162714047, 351405227, 1071724200, + 3125337328, 3159822479, 3228316108, 1071721149, 3010241991, 3158422804, + 2875075254, 1071718107, 4144233330, 3163333716, 3490863953, 1071715073, + 960797498, 3162948880, 685187902, 1071712048, 378731989, 1014843115, + 2952712987, 1071709030, 3293494651, 3160120301, 1608493509, 1071706021, + 3159622171, 3162807737, 852742562, 1071703020, 667253586, 1009793559, + 590962156, 1071700027, 3829346666, 3163275597, 728909815, 1071697042, + 383930225, 1015029468, 1172597893, 1071694065, 114433263, 1015347593, + 1828292879, 1071691096, 1255956747, 1015588398, 2602514713, 1071688135, + 2268929336, 1014354284, 3402036099, 1071685182, 405889334, 1015105656, + 4133881824, 1071682237, 2148155345, 3162931299, 410360776, 1071679301, + 1269990655, 1011975870, 728934454, 1071676372, 1413842688, 1014178612, + 702412510, 1071673451, 3803266087, 3162280415, 238821257, 1071670538, + 1469694871, 3162884987, 3541402996, 1071667632, 2759177317, 1014854626, + 1928746161, 1071664735, 983617676, 1014285177, 3899555717, 1071661845, + 427280750, 3162546972, 772914124, 1071658964, 4004372762, 1012230161, + 1048019041, 1071656090, 1398474845, 3160510595, 339411585, 1071653224, + 264588982, 3161636657, 2851812149, 1071650365, 2595802551, 1015767337, + 4200250559, 1071647514, 2808127345, 3161781938 +}; + +#define __ _masm-> + +address StubGenerator::generate_libmTanh() { + StubCodeMark mark(this, "StubRoutines", "libmTanh"); + address start = __ pc(); + + Label L_2TAG_PACKET_0_0_1, L_2TAG_PACKET_1_0_1, L_2TAG_PACKET_2_0_1, L_2TAG_PACKET_3_0_1; + Label L_2TAG_PACKET_4_0_1, L_2TAG_PACKET_5_0_1; + Label B1_2, B1_4; + + address HALFMASK = (address)_HALFMASK; + address ONEMASK = (address)_ONEMASK; + address TWOMASK = (address)_TWOMASK; + address MASK3 = (address)_MASK3; + address RMASK = (address)_RMASK; + address L2E = (address)_L2E; + address Shifter = (address)_Shifter; + address cv = (address)_cv; + address pv = (address)_pv; + address T2_neg_f = (address) _T2_neg_f; + + __ enter(); // required for proper stackwalking of RuntimeStub frame + + __ bind(B1_2); + __ movsd(xmm3, ExternalAddress(HALFMASK), r11 /*rscratch*/); + __ xorpd(xmm4, xmm4); + __ movsd(xmm1, ExternalAddress(L2E), r11 /*rscratch*/); + __ movsd(xmm2, ExternalAddress(L2E + 8), r11 /*rscratch*/); + __ movl(rax, 32768); + __ pinsrw(xmm4, rax, 3); + __ movsd(xmm6, ExternalAddress(Shifter), r11 /*rscratch*/); + __ pextrw(rcx, xmm0, 3); + __ andpd(xmm3, xmm0); + __ andnpd(xmm4, xmm0); + __ pshufd(xmm5, xmm4, 68); + __ movl(rdx, 32768); + __ andl(rdx, rcx); + __ andl(rcx, 32767); + __ subl(rcx, 16304); + __ cmpl(rcx, 144); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_0_0_1); + __ subsd(xmm4, xmm3); + __ mulsd(xmm3, xmm1); + __ mulsd(xmm2, xmm5); + __ cvtsd2siq(rax, xmm3); + __ movq(xmm7, xmm3); + __ addsd(xmm3, xmm6); + __ mulsd(xmm1, xmm4); + __ movsd(xmm4, ExternalAddress(ONEMASK), r11 /*rscratch*/); + __ subsd(xmm3, xmm6); + __ xorpd(xmm0, xmm0); + __ addsd(xmm2, xmm1); + __ subsd(xmm7, xmm3); + __ movdqu(xmm6, ExternalAddress(cv), r11 /*rscratch*/); + __ addsd(xmm2, xmm7); + __ movl(rcx, 255); + __ andl(rcx, rax); + __ addl(rcx, rcx); + __ lea(r8, ExternalAddress(T2_neg_f)); + __ movdqu(xmm5, Address(r8, rcx, Address::times(8))); + __ shrl(rax, 4); + __ andl(rax, 65520); + __ subl(rax, 16368); + __ negl(rax); + __ pinsrw(xmm0, rax, 3); + __ movdqu(xmm1, ExternalAddress(cv + 16), r11 /*rscratch*/); + __ pshufd(xmm0, xmm0, 68); + __ mulpd(xmm0, xmm5); + __ movsd(xmm7, ExternalAddress(cv + 32), r11 /*rscratch*/); + __ pshufd(xmm2, xmm2, 68); + __ movq(xmm5, xmm4); + __ addsd(xmm4, xmm0); + __ mulpd(xmm6, xmm2); + __ mulsd(xmm7, xmm2); + __ mulpd(xmm2, xmm2); + __ addpd(xmm1, xmm6); + __ mulsd(xmm2, xmm2); + __ movsd(xmm3, ExternalAddress(ONEMASK), r11 /*rscratch*/); + __ mulpd(xmm1, xmm2); + __ pshufd(xmm6, xmm1, 78); + __ addsd(xmm1, xmm6); + __ movq(xmm6, xmm1); + __ addsd(xmm1, xmm7); + __ mulsd(xmm1, xmm0); + __ addsd(xmm1, xmm4); + __ andpd(xmm4, ExternalAddress(MASK3), r11 /*rscratch*/); + __ divsd(xmm5, xmm1); + __ subsd(xmm3, xmm4); + __ pshufd(xmm1, xmm0, 238); + __ addsd(xmm3, xmm0); + __ movq(xmm2, xmm4); + __ addsd(xmm3, xmm1); + __ mulsd(xmm1, xmm7); + __ mulsd(xmm7, xmm0); + __ addsd(xmm3, xmm1); + __ addsd(xmm4, xmm7); + __ movsd(xmm1, ExternalAddress(RMASK), r11 /*rscratch*/); + __ mulsd(xmm6, xmm0); + __ andpd(xmm4, ExternalAddress(MASK3), r11 /*rscratch*/); + __ addsd(xmm3, xmm6); + __ movq(xmm6, xmm4); + __ subsd(xmm2, xmm4); + __ addsd(xmm2, xmm7); + __ movsd(xmm7, ExternalAddress(ONEMASK), r11 /*rscratch*/); + __ andpd(xmm5, xmm1); + __ addsd(xmm3, xmm2); + __ mulsd(xmm4, xmm5); + __ xorpd(xmm2, xmm2); + __ mulsd(xmm3, xmm5); + __ subsd(xmm6, ExternalAddress(TWOMASK), r11 /*rscratch*/); + __ subsd(xmm4, xmm7); + __ xorl(rdx, 32768); + __ pinsrw(xmm2, rdx, 3); + __ addsd(xmm4, xmm3); + __ mulsd(xmm6, xmm5); + __ movq(xmm1, xmm3); + __ mulsd(xmm3, xmm4); + __ movq(xmm0, xmm6); + __ mulsd(xmm6, xmm4); + __ subsd(xmm1, xmm3); + __ subsd(xmm1, xmm6); + __ addsd(xmm0, xmm1); + __ xorpd(xmm0, xmm2); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_0_0_1); + __ addl(rcx, 960); + __ cmpl(rcx, 1104); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_1_0_1); + __ movdqu(xmm2, ExternalAddress(pv), r11 /*rscratch*/); + __ pshufd(xmm1, xmm0, 68); + __ movdqu(xmm3, ExternalAddress(pv + 16), r11 /*rscratch*/); + __ mulpd(xmm1, xmm1); + __ movdqu(xmm4, ExternalAddress(pv + 32), r11 /*rscratch*/); + __ mulpd(xmm2, xmm1); + __ pshufd(xmm5, xmm1, 68); + __ addpd(xmm2, xmm3); + __ mulsd(xmm5, xmm5); + __ mulpd(xmm2, xmm1); + __ mulsd(xmm5, xmm5); + __ addpd(xmm2, xmm4); + __ mulpd(xmm2, xmm5); + __ pshufd(xmm5, xmm2, 238); + __ addsd(xmm2, xmm5); + __ mulsd(xmm2, xmm0); + __ addsd(xmm0, xmm2); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_1_0_1); + __ addl(rcx, 15344); + __ cmpl(rcx, 16448); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_2_0_1); + __ cmpl(rcx, 16); + __ jcc(Assembler::below, L_2TAG_PACKET_3_0_1); + __ xorpd(xmm2, xmm2); + __ movl(rax, 17392); + __ pinsrw(xmm2, rax, 3); + __ mulsd(xmm2, xmm0); + __ addsd(xmm2, xmm0); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_3_0_1); + __ movq(xmm2, xmm0); + __ mulsd(xmm2, xmm2); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_2_0_1); + __ cmpl(rcx, 32752); + __ jcc(Assembler::aboveEqual, L_2TAG_PACKET_4_0_1); + __ xorpd(xmm2, xmm2); + __ movl(rcx, 15344); + __ pinsrw(xmm2, rcx, 3); + __ movq(xmm3, xmm2); + __ mulsd(xmm2, xmm2); + __ addsd(xmm2, xmm3); + + __ bind(L_2TAG_PACKET_5_0_1); + __ xorpd(xmm0, xmm0); + __ orl(rdx, 16368); + __ pinsrw(xmm0, rdx, 3); + __ jmp(B1_4); + + __ bind(L_2TAG_PACKET_4_0_1); + __ movq(xmm2, xmm0); + __ movdl(rax, xmm0); + __ psrlq(xmm2, 20); + __ movdl(rcx, xmm2); + __ orl(rcx, rax); + __ cmpl(rcx, 0); + __ jcc(Assembler::equal, L_2TAG_PACKET_5_0_1); + __ addsd(xmm0, xmm0); + + __ bind(B1_4); + __ leave(); // required for proper stackwalking of RuntimeStub frame + __ ret(0); + + return start; +} + +#undef __ diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp index ba9eb32e8c13e..75611524e3b0a 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_32.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -373,6 +373,10 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M // [ lo(arg) ] // [ hi(arg) ] // + if (kind == Interpreter::java_lang_math_tanh) { + return nullptr; + } + if (kind == Interpreter::java_lang_math_fmaD) { if (!UseFMA) { return nullptr; // Generate a vanilla entry diff --git a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp index 26eea4c1d6a5f..5ea2d8eba259b 100644 --- a/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp +++ b/src/hotspot/cpu/x86/templateInterpreterGenerator_x86_64.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -465,6 +465,10 @@ address TemplateInterpreterGenerator::generate_math_entry(AbstractInterpreter::M } else { __ call_VM_leaf0(CAST_FROM_FN_PTR(address, SharedRuntime::dtan)); } + } else if (kind == Interpreter::java_lang_math_tanh) { + assert(StubRoutines::dtanh() != nullptr, "not initialized"); + __ movdbl(xmm0, Address(rsp, wordSize)); + __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::dtanh()))); } else if (kind == Interpreter::java_lang_math_abs) { assert(StubRoutines::x86::double_sign_mask() != nullptr, "not initialized"); __ movdbl(xmm0, Address(rsp, wordSize)); diff --git a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp index b80124cc34e43..f967fee930579 100644 --- a/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp +++ b/src/hotspot/os/linux/gc/z/zPhysicalMemoryBacking_linux.cpp @@ -103,14 +103,14 @@ #define ZFILENAME_HEAP "java_heap" // Preferred tmpfs mount points, ordered by priority -static const char* z_preferred_tmpfs_mountpoints[] = { +static const char* ZPreferredTmpfsMountpoints[] = { "/dev/shm", "/run/shm", nullptr }; // Preferred hugetlbfs mount points, ordered by priority -static const char* z_preferred_hugetlbfs_mountpoints[] = { +static const char* ZPreferredHugetlbfsMountpoints[] = { "/dev/hugepages", "/hugepages", nullptr @@ -226,8 +226,8 @@ int ZPhysicalMemoryBacking::create_file_fd(const char* name) const { ? ZFILESYSTEM_HUGETLBFS : ZFILESYSTEM_TMPFS; const char** const preferred_mountpoints = ZLargePages::is_explicit() - ? z_preferred_hugetlbfs_mountpoints - : z_preferred_tmpfs_mountpoints; + ? ZPreferredHugetlbfsMountpoints + : ZPreferredTmpfsMountpoints; // Find mountpoint ZMountPoint mountpoint(filesystem, preferred_mountpoints); diff --git a/src/hotspot/os/windows/os_windows.cpp b/src/hotspot/os/windows/os_windows.cpp index 1acce2540a855..817757f1ac6a2 100644 --- a/src/hotspot/os/windows/os_windows.cpp +++ b/src/hotspot/os/windows/os_windows.cpp @@ -1947,7 +1947,10 @@ void os::win32::print_windows_version(outputStream* st) { // - 2016 GA 10/2016 build: 14393 // - 2019 GA 11/2018 build: 17763 // - 2022 GA 08/2021 build: 20348 - if (build_number > 20347) { + // - 2025 Preview build : 26040 + if (build_number > 26039) { + st->print("Server 2025"); + } else if (build_number > 20347) { st->print("Server 2022"); } else if (build_number > 17762) { st->print("Server 2019"); @@ -4090,6 +4093,39 @@ int os::win32::_build_minor = 0; bool os::win32::_processor_group_warning_displayed = false; bool os::win32::_job_object_processor_group_warning_displayed = false; +void getWindowsInstallationType(char* buffer, int bufferSize) { + HKEY hKey; + const char* subKey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"; + const char* valueName = "InstallationType"; + + DWORD valueLength = bufferSize; + + // Initialize buffer with empty string + buffer[0] = '\0'; + + // Open the registry key + if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) { + // Return empty buffer if key cannot be opened + return; + } + + // Query the value + if (RegQueryValueExA(hKey, valueName, NULL, NULL, (LPBYTE)buffer, &valueLength) != ERROR_SUCCESS) { + RegCloseKey(hKey); + buffer[0] = '\0'; + return; + } + + RegCloseKey(hKey); +} + +bool isNanoServer() { + const int BUFFER_SIZE = 256; + char installationType[BUFFER_SIZE]; + getWindowsInstallationType(installationType, BUFFER_SIZE); + return (strcmp(installationType, "Nano Server") == 0); +} + void os::win32::initialize_windows_version() { assert(_major_version == 0, "windows version already initialized."); @@ -4107,7 +4143,13 @@ void os::win32::initialize_windows_version() { warning("Attempt to determine system directory failed: %s", buf_len != 0 ? error_msg_buffer : ""); return; } - strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret); + + if (isNanoServer()) { + // On Windows Nanoserver the kernel32.dll is located in the forwarders subdirectory + strncat(kernel32_path, "\\forwarders\\kernel32.dll", MAX_PATH - ret); + } else { + strncat(kernel32_path, "\\kernel32.dll", MAX_PATH - ret); + } DWORD version_size = GetFileVersionInfoSize(kernel32_path, nullptr); if (version_size == 0) { diff --git a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp index a7dc84770f84c..368d6c971fae0 100644 --- a/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp +++ b/src/hotspot/os_cpu/linux_riscv/orderAccess_linux_riscv.hpp @@ -54,6 +54,24 @@ inline void OrderAccess::fence() { } inline void OrderAccess::cross_modify_fence_impl() { + // From 3 “Zifencei” Instruction-Fetch Fence, Version 2.0 + // "RISC-V does not guarantee that stores to instruction memory will be made + // visible to instruction fetches on a RISC-V hart until that hart executes a + // FENCE.I instruction. A FENCE.I instruction ensures that a subsequent + // instruction fetch on a RISC-V hart will see any previous data stores + // already visible to the same RISC-V hart. FENCE.I does not ensure that other + // RISC-V harts’ instruction fetches will observe the local hart’s stores in a + // multiprocessor system." + // + // Hence to be able to use fence.i directly we need a kernel that supports + // PR_RISCV_CTX_SW_FENCEI_ON. Thus if context switch to another hart we are + // ensured that instruction fetch will see any previous data stores + // + // The alternative is using full system IPI (system wide icache sync) then + // this barrier is not strictly needed. As this is emitted in runtime slow-path + // we will just always emit it, typically after a safepoint. + guarantee(VM_Version::supports_fencei_barrier(), "Linux kernel require fence.i"); + __asm__ volatile("fence.i" : : : "memory"); } #endif // OS_CPU_LINUX_RISCV_ORDERACCESS_LINUX_RISCV_HPP diff --git a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp index 3f9f26b525ba5..a3a226502f6fc 100644 --- a/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp +++ b/src/hotspot/os_cpu/linux_riscv/vm_version_linux_riscv.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #ifndef HWCAP_ISA_I #define HWCAP_ISA_I nth_bit('I' - 'A') @@ -82,6 +83,23 @@ __v; \ }) +// prctl PR_RISCV_SET_ICACHE_FLUSH_CTX is from Linux 6.9 +#ifndef PR_RISCV_SET_ICACHE_FLUSH_CTX +#define PR_RISCV_SET_ICACHE_FLUSH_CTX 71 +#endif +#ifndef PR_RISCV_CTX_SW_FENCEI_ON +#define PR_RISCV_CTX_SW_FENCEI_ON 0 +#endif +#ifndef PR_RISCV_CTX_SW_FENCEI_OFF +#define PR_RISCV_CTX_SW_FENCEI_OFF 1 +#endif +#ifndef PR_RISCV_SCOPE_PER_PROCESS +#define PR_RISCV_SCOPE_PER_PROCESS 0 +#endif +#ifndef PR_RISCV_SCOPE_PER_THREAD +#define PR_RISCV_SCOPE_PER_THREAD 1 +#endif + uint32_t VM_Version::cpu_vector_length() { assert(ext_V.enabled(), "should not call this"); return (uint32_t)read_csr(CSR_VLENB); @@ -102,6 +120,7 @@ void VM_Version::setup_cpu_available_features() { if (!RiscvHwprobe::probe_features()) { os_aux_features(); } + char* uarch = os_uarch_additional_features(); vendor_features(); @@ -155,6 +174,24 @@ void VM_Version::setup_cpu_available_features() { i++; } + // Linux kernel require Zifencei + if (!ext_Zifencei.enabled()) { + log_info(os, cpu)("Zifencei not found, required by Linux, enabling."); + ext_Zifencei.enable_feature(); + } + + if (UseCtxFencei) { + // Note that we can set this up only for effected threads + // via PR_RISCV_SCOPE_PER_THREAD, i.e. on VM attach/deattach. + int ret = prctl(PR_RISCV_SET_ICACHE_FLUSH_CTX, PR_RISCV_CTX_SW_FENCEI_ON, PR_RISCV_SCOPE_PER_PROCESS); + if (ret == 0) { + log_debug(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) enabled."); + } else { + FLAG_SET_ERGO(UseCtxFencei, false); + log_info(os, cpu)("UseCtxFencei (PR_RISCV_CTX_SW_FENCEI_ON) disabled, unsupported by kernel."); + } + } + _features_string = os::strdup(buf); } diff --git a/src/hotspot/share/c1/c1_Compiler.cpp b/src/hotspot/share/c1/c1_Compiler.cpp index 04f54170d7208..aa1be5ec66c15 100644 --- a/src/hotspot/share/c1/c1_Compiler.cpp +++ b/src/hotspot/share/c1/c1_Compiler.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -173,6 +173,9 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + #if defined(AMD64) + case vmIntrinsics::_dtanh: + #endif case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: diff --git a/src/hotspot/share/c1/c1_GraphBuilder.cpp b/src/hotspot/share/c1/c1_GraphBuilder.cpp index a2e903edc342f..02be6f8d49e4a 100644 --- a/src/hotspot/share/c1/c1_GraphBuilder.cpp +++ b/src/hotspot/share/c1/c1_GraphBuilder.cpp @@ -3339,6 +3339,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) case vmIntrinsics::_dsin : // fall through case vmIntrinsics::_dcos : // fall through case vmIntrinsics::_dtan : // fall through + case vmIntrinsics::_dtanh : // fall through case vmIntrinsics::_dlog : // fall through case vmIntrinsics::_dlog10 : // fall through case vmIntrinsics::_dexp : // fall through diff --git a/src/hotspot/share/c1/c1_LIR.hpp b/src/hotspot/share/c1/c1_LIR.hpp index c875470c3a813..97f2ab7d06b0b 100644 --- a/src/hotspot/share/c1/c1_LIR.hpp +++ b/src/hotspot/share/c1/c1_LIR.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -2042,8 +2042,9 @@ class LIR_OpProfileCall : public LIR_Op { virtual void print_instr(outputStream* out) const PRODUCT_RETURN; bool should_profile_receiver_type() const { bool callee_is_static = _profiled_callee->is_loaded() && _profiled_callee->is_static(); + bool callee_is_private = _profiled_callee->is_loaded() && _profiled_callee->is_private(); Bytecodes::Code bc = _profiled_method->java_code_at_bci(_profiled_bci); - bool call_is_virtual = (bc == Bytecodes::_invokevirtual && !_profiled_callee->can_be_statically_bound()) || bc == Bytecodes::_invokeinterface; + bool call_is_virtual = (bc == Bytecodes::_invokevirtual && !callee_is_private) || bc == Bytecodes::_invokeinterface; return C1ProfileVirtualCalls && call_is_virtual && !callee_is_static; } }; diff --git a/src/hotspot/share/c1/c1_LIRGenerator.cpp b/src/hotspot/share/c1/c1_LIRGenerator.cpp index 4e63736503fe0..74fdf7a5b76a3 100644 --- a/src/hotspot/share/c1/c1_LIRGenerator.cpp +++ b/src/hotspot/share/c1/c1_LIRGenerator.cpp @@ -2971,6 +2971,7 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) { case vmIntrinsics::_dsqrt: // fall through case vmIntrinsics::_dsqrt_strict: // fall through case vmIntrinsics::_dtan: // fall through + case vmIntrinsics::_dtanh: // fall through case vmIntrinsics::_dsin : // fall through case vmIntrinsics::_dcos : // fall through case vmIntrinsics::_dexp : // fall through diff --git a/src/hotspot/share/c1/c1_Runtime1.cpp b/src/hotspot/share/c1/c1_Runtime1.cpp index 5b44d5c0f1983..915f00f77c523 100644 --- a/src/hotspot/share/c1/c1_Runtime1.cpp +++ b/src/hotspot/share/c1/c1_Runtime1.cpp @@ -347,6 +347,7 @@ const char* Runtime1::name_for_address(address entry) { FUNCTION_CASE(entry, StubRoutines::dsin()); FUNCTION_CASE(entry, StubRoutines::dcos()); FUNCTION_CASE(entry, StubRoutines::dtan()); + FUNCTION_CASE(entry, StubRoutines::dtanh()); #undef FUNCTION_CASE diff --git a/src/hotspot/share/cds/archiveHeapWriter.cpp b/src/hotspot/share/cds/archiveHeapWriter.cpp index d8ee7155452ff..853d459c691dd 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.cpp +++ b/src/hotspot/share/cds/archiveHeapWriter.cpp @@ -88,7 +88,6 @@ void ArchiveHeapWriter::init() { _native_pointers = new GrowableArrayCHeap(2048); _source_objs = new GrowableArrayCHeap(10000); - guarantee(UseG1GC, "implementation limitation"); guarantee(MIN_GC_REGION_ALIGNMENT <= G1HeapRegion::min_region_size_in_words() * HeapWordSize, "must be"); } } @@ -249,11 +248,16 @@ void ArchiveHeapWriter::copy_roots_to_buffer(GrowableArrayCHeap_rank; int rank_b = b->_rank; @@ -452,26 +451,30 @@ size_t ArchiveHeapWriter::copy_one_source_obj_to_buffer(oop src_obj) { void ArchiveHeapWriter::set_requested_address(ArchiveHeapInfo* info) { assert(!info->is_used(), "only set once"); - assert(UseG1GC, "must be"); - address heap_end = (address)G1CollectedHeap::heap()->reserved().end(); - log_info(cds, heap)("Heap end = %p", heap_end); size_t heap_region_byte_size = _buffer_used; assert(heap_region_byte_size > 0, "must archived at least one object!"); - if (UseCompressedOops) { - _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes); + if (UseG1GC) { + address heap_end = (address)G1CollectedHeap::heap()->reserved().end(); + log_info(cds, heap)("Heap end = %p", heap_end); + _requested_bottom = align_down(heap_end - heap_region_byte_size, G1HeapRegion::GrainBytes); + _requested_bottom = align_down(_requested_bottom, MIN_GC_REGION_ALIGNMENT); + assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity"); + } else { + _requested_bottom = align_up(CompressedOops::begin(), MIN_GC_REGION_ALIGNMENT); + } } else { // We always write the objects as if the heap started at this address. This // makes the contents of the archive heap deterministic. // // Note that at runtime, the heap address is selected by the OS, so the archive // heap will not be mapped at 0x10000000, and the contents need to be patched. - _requested_bottom = (address)NOCOOPS_REQUESTED_BASE; + _requested_bottom = align_up((address)NOCOOPS_REQUESTED_BASE, MIN_GC_REGION_ALIGNMENT); } - assert(is_aligned(_requested_bottom, G1HeapRegion::GrainBytes), "sanity"); + assert(is_aligned(_requested_bottom, MIN_GC_REGION_ALIGNMENT), "sanity"); _requested_top = _requested_bottom + _buffer_used; diff --git a/src/hotspot/share/cds/archiveHeapWriter.hpp b/src/hotspot/share/cds/archiveHeapWriter.hpp index 961d2b52133f8..29ea50ba5fe86 100644 --- a/src/hotspot/share/cds/archiveHeapWriter.hpp +++ b/src/hotspot/share/cds/archiveHeapWriter.hpp @@ -111,11 +111,10 @@ class ArchiveHeapWriter : AllStatic { public: static const intptr_t NOCOOPS_REQUESTED_BASE = 0x10000000; - // The minimum region size of all collectors that are supported by CDS in - // ArchiveHeapLoader::can_map() mode. Currently only G1 is supported. G1's region size - // depends on -Xmx, but can never be smaller than 1 * M. - // (TODO: Perhaps change to 256K to be compatible with Shenandoah) - static constexpr int MIN_GC_REGION_ALIGNMENT = 1 * M; + // The minimum region size of all collectors that are supported by CDS. + // G1 heap region size can never be smaller than 1M. + // Shenandoah heap region size can never be smaller than 256K. + static constexpr int MIN_GC_REGION_ALIGNMENT = 256 * K; private: class EmbeddedOopRelocator; diff --git a/src/hotspot/share/cds/filemap.cpp b/src/hotspot/share/cds/filemap.cpp index 7bbb9688015e7..c935541d7cf0a 100644 --- a/src/hotspot/share/cds/filemap.cpp +++ b/src/hotspot/share/cds/filemap.cpp @@ -1581,39 +1581,38 @@ static size_t write_bitmap(const CHeapBitMap* map, char* output, size_t offset) return offset + size_in_bytes; } -// The start of the archived heap has many primitive arrays (String -// bodies) that are not marked by the oop/ptr maps. So we must have -// lots of leading zeros. -size_t FileMapInfo::remove_bitmap_leading_zeros(CHeapBitMap* map) { - size_t old_zeros = map->find_first_set_bit(0); +// The sorting code groups the objects with non-null oop/ptrs together. +// Relevant bitmaps then have lots of leading and trailing zeros, which +// we do not have to store. +size_t FileMapInfo::remove_bitmap_zeros(CHeapBitMap* map) { + BitMap::idx_t first_set = map->find_first_set_bit(0); + BitMap::idx_t last_set = map->find_last_set_bit(0); size_t old_size = map->size(); // Slice and resize bitmap - map->truncate(old_zeros, map->size()); + map->truncate(first_set, last_set + 1); - DEBUG_ONLY( - size_t new_zeros = map->find_first_set_bit(0); - assert(new_zeros == 0, "Should have removed leading zeros"); - ) + assert(map->at(0), "First bit should be set"); + assert(map->at(map->size() - 1), "Last bit should be set"); assert(map->size() <= old_size, "sanity"); - return old_zeros; + + return first_set; } char* FileMapInfo::write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap, ArchiveHeapInfo* heap_info, size_t &size_in_bytes) { - size_t removed_rw_zeros = remove_bitmap_leading_zeros(rw_ptrmap); - size_t removed_ro_zeros = remove_bitmap_leading_zeros(ro_ptrmap); - header()->set_rw_ptrmap_start_pos(removed_rw_zeros); - header()->set_ro_ptrmap_start_pos(removed_ro_zeros); + size_t removed_rw_leading_zeros = remove_bitmap_zeros(rw_ptrmap); + size_t removed_ro_leading_zeros = remove_bitmap_zeros(ro_ptrmap); + header()->set_rw_ptrmap_start_pos(removed_rw_leading_zeros); + header()->set_ro_ptrmap_start_pos(removed_ro_leading_zeros); size_in_bytes = rw_ptrmap->size_in_bytes() + ro_ptrmap->size_in_bytes(); if (heap_info->is_used()) { - // Remove leading zeros - size_t removed_oop_zeros = remove_bitmap_leading_zeros(heap_info->oopmap()); - size_t removed_ptr_zeros = remove_bitmap_leading_zeros(heap_info->ptrmap()); - - header()->set_heap_oopmap_start_pos(removed_oop_zeros); - header()->set_heap_ptrmap_start_pos(removed_ptr_zeros); + // Remove leading and trailing zeros + size_t removed_oop_leading_zeros = remove_bitmap_zeros(heap_info->oopmap()); + size_t removed_ptr_leading_zeros = remove_bitmap_zeros(heap_info->ptrmap()); + header()->set_heap_oopmap_start_pos(removed_oop_leading_zeros); + header()->set_heap_ptrmap_start_pos(removed_ptr_leading_zeros); size_in_bytes += heap_info->oopmap()->size_in_bytes(); size_in_bytes += heap_info->ptrmap()->size_in_bytes(); diff --git a/src/hotspot/share/cds/filemap.hpp b/src/hotspot/share/cds/filemap.hpp index aa728b9d4949f..1bf2510a3351c 100644 --- a/src/hotspot/share/cds/filemap.hpp +++ b/src/hotspot/share/cds/filemap.hpp @@ -445,7 +445,7 @@ class FileMapInfo : public CHeapObj { void write_header(); void write_region(int region, char* base, size_t size, bool read_only, bool allow_exec); - size_t remove_bitmap_leading_zeros(CHeapBitMap* map); + size_t remove_bitmap_zeros(CHeapBitMap* map); char* write_bitmap_region(CHeapBitMap* rw_ptrmap, CHeapBitMap* ro_ptrmap, ArchiveHeapInfo* heap_info, size_t &size_in_bytes); size_t write_heap_region(ArchiveHeapInfo* heap_info); diff --git a/src/hotspot/share/cds/heapShared.cpp b/src/hotspot/share/cds/heapShared.cpp index 2bf75a5ba6512..1fddcb0d81f8a 100644 --- a/src/hotspot/share/cds/heapShared.cpp +++ b/src/hotspot/share/cds/heapShared.cpp @@ -471,11 +471,13 @@ void HeapShared::archive_objects(ArchiveHeapInfo *heap_info) { // Cache for recording where the archived objects are copied to create_archived_object_cache(); - log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", - UseCompressedOops ? p2i(CompressedOops::begin()) : - p2i((address)G1CollectedHeap::heap()->reserved().start()), - UseCompressedOops ? p2i(CompressedOops::end()) : - p2i((address)G1CollectedHeap::heap()->reserved().end())); + if (UseCompressedOops || UseG1GC) { + log_info(cds)("Heap range = [" PTR_FORMAT " - " PTR_FORMAT "]", + UseCompressedOops ? p2i(CompressedOops::begin()) : + p2i((address)G1CollectedHeap::heap()->reserved().start()), + UseCompressedOops ? p2i(CompressedOops::end()) : + p2i((address)G1CollectedHeap::heap()->reserved().end())); + } copy_objects(); CDSHeapVerifier::verify(); diff --git a/src/hotspot/share/cds/heapShared.hpp b/src/hotspot/share/cds/heapShared.hpp index 9bb85db0fe9d2..01610ebe64e15 100644 --- a/src/hotspot/share/cds/heapShared.hpp +++ b/src/hotspot/share/cds/heapShared.hpp @@ -143,13 +143,13 @@ class HeapShared: AllStatic { friend class VerifySharedOopClosure; public: - // Can this VM write a heap region into the CDS archive? Currently only G1+compressed{oops,cp} + // Can this VM write a heap region into the CDS archive? Currently only {G1|Parallel|Serial}+compressed_cp static bool can_write() { CDS_JAVA_HEAP_ONLY( if (_disable_writing) { return false; } - return (UseG1GC && UseCompressedClassPointers); + return (UseG1GC || UseParallelGC || UseSerialGC) && UseCompressedClassPointers; ) NOT_CDS_JAVA_HEAP(return false;) } diff --git a/src/hotspot/share/classfile/classFileParser.cpp b/src/hotspot/share/classfile/classFileParser.cpp index 60fed287df594..c8e95149b7c1a 100644 --- a/src/hotspot/share/classfile/classFileParser.cpp +++ b/src/hotspot/share/classfile/classFileParser.cpp @@ -1150,30 +1150,40 @@ static void parse_annotations(const ConstantPool* const cp, if (AnnotationCollector::_unknown == id) continue; coll->set_annotation(id); if (AnnotationCollector::_java_lang_Deprecated == id) { - assert(count <= 2, "change this if more element-value pairs are added to the @Deprecated annotation"); - // @Deprecated can specify forRemoval=true + // @Deprecated can specify forRemoval=true, which we need + // to record for JFR to use. If the annotation is not well-formed + // then we may not be able to determine that. const u1* offset = abase + member_off; - for (int i = 0; i < count; ++i) { + // There are only 2 members in @Deprecated. + int n_members = MIN2(count, 2); + for (int i = 0; i < n_members; ++i) { int member_index = Bytes::get_Java_u2((address)offset); offset += 2; member = check_symbol_at(cp, member_index); - if (member == vmSymbols::since()) { - assert(*((address)offset) == s_tag_val, "invariant"); + if (member == vmSymbols::since() && + (*((address)offset) == s_tag_val)) { + // Found `since` first so skip over it offset += 3; - continue; } - if (member == vmSymbols::for_removal()) { - assert(*((address)offset) == b_tag_val, "invariant"); + else if (member == vmSymbols::for_removal() && + (*((address)offset) == b_tag_val)) { const u2 boolean_value_index = Bytes::get_Java_u2((address)offset + 1); - if (cp->int_at(boolean_value_index) == 1) { + // No guarantee the entry is valid so check it refers to an int in the CP. + if (cp->is_within_bounds(boolean_value_index) && + cp->tag_at(boolean_value_index).is_int() && + cp->int_at(boolean_value_index) == 1) { // forRemoval == true coll->set_annotation(AnnotationCollector::_java_lang_Deprecated_for_removal); } + break; // no need to check further + } + else { + // This @Deprecated annotation is malformed so we don't try to + // determine whether forRemoval is set. break; } - } - continue; + continue; // proceed to next annotation } if (AnnotationCollector::_jdk_internal_vm_annotation_Contended == id) { @@ -1194,11 +1204,21 @@ static void parse_annotations(const ConstantPool* const cp, && s_tag_val == *(abase + tag_off) && member == vmSymbols::value_name()) { group_index = Bytes::get_Java_u2((address)abase + s_con_off); - if (cp->symbol_at(group_index)->utf8_length() == 0) { - group_index = 0; // default contended group + // No guarantee the group_index is valid so check it refers to a + // symbol in the CP. + if (cp->is_within_bounds(group_index) && + cp->tag_at(group_index).is_utf8()) { + // Seems valid, so check for empty string and reset + if (cp->symbol_at(group_index)->utf8_length() == 0) { + group_index = 0; // default contended group + } + } else { + // Not valid so use the default + group_index = 0; } } coll->set_contended_group(group_index); + continue; // proceed to next annotation } } } diff --git a/src/hotspot/share/classfile/systemDictionary.cpp b/src/hotspot/share/classfile/systemDictionary.cpp index b9a559cf9779f..bcddddc0c7c78 100644 --- a/src/hotspot/share/classfile/systemDictionary.cpp +++ b/src/hotspot/share/classfile/systemDictionary.cpp @@ -1149,10 +1149,12 @@ InstanceKlass* SystemDictionary::load_shared_class(InstanceKlass* ik, Symbol* class_name = ik->name(); if (!is_shared_class_visible(class_name, ik, pkg_entry, class_loader)) { + ik->set_shared_loading_failed(); return nullptr; } if (!check_shared_class_super_types(ik, class_loader, protection_domain, THREAD)) { + ik->set_shared_loading_failed(); return nullptr; } diff --git a/src/hotspot/share/classfile/systemDictionary.hpp b/src/hotspot/share/classfile/systemDictionary.hpp index ee50aa38dd0cf..04980291716c7 100644 --- a/src/hotspot/share/classfile/systemDictionary.hpp +++ b/src/hotspot/share/classfile/systemDictionary.hpp @@ -293,13 +293,6 @@ class SystemDictionary : AllStatic { const char* message); static const char* find_nest_host_error(const constantPoolHandle& pool, int which); -protected: - static InstanceKlass* _well_known_klasses[]; - -private: - // table of box klasses (int_klass, etc.) - static InstanceKlass* _box_klasses[T_VOID+1]; - static OopHandle _java_system_loader; static OopHandle _java_platform_loader; diff --git a/src/hotspot/share/classfile/vmClasses.cpp b/src/hotspot/share/classfile/vmClasses.cpp index 0b9b437c67b78..b62d699dfe20e 100644 --- a/src/hotspot/share/classfile/vmClasses.cpp +++ b/src/hotspot/share/classfile/vmClasses.cpp @@ -45,14 +45,6 @@ InstanceKlass* vmClasses::_klasses[static_cast(vmClassID::LIMIT)] = { nullptr /*, nullptr...*/ }; InstanceKlass* vmClasses::_box_klasses[T_VOID+1] = { nullptr /*, nullptr...*/ }; - -// CDS: scan and relocate all classes referenced by _klasses[]. -void vmClasses::metaspace_pointers_do(MetaspaceClosure* it) { - for (auto id : EnumRange{}) { - it->push(klass_addr_at(id)); - } -} - bool vmClasses::is_loaded(InstanceKlass* klass) { return klass != nullptr && klass->is_loaded(); } @@ -205,8 +197,6 @@ void vmClasses::resolve_all(TRAPS) { _box_klasses[T_SHORT] = vmClasses::Short_klass(); _box_klasses[T_INT] = vmClasses::Integer_klass(); _box_klasses[T_LONG] = vmClasses::Long_klass(); - //_box_klasses[T_OBJECT] = vmClasses::object_klass(); - //_box_klasses[T_ARRAY] = vmClasses::object_klass(); #ifdef ASSERT if (CDSConfig::is_using_archive()) { diff --git a/src/hotspot/share/classfile/vmClasses.hpp b/src/hotspot/share/classfile/vmClasses.hpp index f2b8c5666eeb1..4fa078c50cd80 100644 --- a/src/hotspot/share/classfile/vmClasses.hpp +++ b/src/hotspot/share/classfile/vmClasses.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -32,7 +32,6 @@ class ClassLoaderData; class InstanceKlass; -class MetaspaceClosure; class vmClasses : AllStatic { friend class VMStructs; @@ -95,7 +94,6 @@ class vmClasses : AllStatic { return &_klasses[as_int(id)]; } - static void metaspace_pointers_do(MetaspaceClosure* it); static void resolve_all(TRAPS); static BasicType box_klass_type(Klass* k); // inverse of box_klass diff --git a/src/hotspot/share/classfile/vmIntrinsics.cpp b/src/hotspot/share/classfile/vmIntrinsics.cpp index b470eb9b8380d..5e352e42efbc1 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.cpp +++ b/src/hotspot/share/classfile/vmIntrinsics.cpp @@ -90,6 +90,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + case vmIntrinsics::_dtanh: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: @@ -141,6 +142,7 @@ bool vmIntrinsics::can_trap(vmIntrinsics::ID id) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + case vmIntrinsics::_dtanh: case vmIntrinsics::_dlog: case vmIntrinsics::_dlog10: case vmIntrinsics::_dexp: @@ -288,6 +290,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + case vmIntrinsics::_dtanh: case vmIntrinsics::_dlog: case vmIntrinsics::_dexp: case vmIntrinsics::_dpow: diff --git a/src/hotspot/share/classfile/vmIntrinsics.hpp b/src/hotspot/share/classfile/vmIntrinsics.hpp index 4b772c171d5a6..af1c2b31a9809 100644 --- a/src/hotspot/share/classfile/vmIntrinsics.hpp +++ b/src/hotspot/share/classfile/vmIntrinsics.hpp @@ -135,7 +135,7 @@ class methodHandle; do_name(log_name,"log") do_name(log10_name,"log10") do_name(pow_name,"pow") \ do_name(exp_name,"exp") do_name(min_name,"min") do_name(max_name,"max") \ do_name(floor_name, "floor") do_name(ceil_name, "ceil") do_name(rint_name, "rint") \ - do_name(round_name, "round") \ + do_name(round_name, "round") do_name(tanh_name,"tanh") \ \ do_name(addExact_name,"addExact") \ do_name(decrementExact_name,"decrementExact") \ @@ -161,6 +161,7 @@ class methodHandle; do_intrinsic(_dcos, java_lang_Math, cos_name, double_double_signature, F_S) \ do_intrinsic(_dtan, java_lang_Math, tan_name, double_double_signature, F_S) \ do_intrinsic(_datan2, java_lang_Math, atan2_name, double2_double_signature, F_S) \ + do_intrinsic(_dtanh, java_lang_Math, tanh_name, double_double_signature, F_S) \ do_intrinsic(_dsqrt, java_lang_Math, sqrt_name, double_double_signature, F_S) \ do_intrinsic(_dlog, java_lang_Math, log_name, double_double_signature, F_S) \ do_intrinsic(_dlog10, java_lang_Math, log10_name, double_double_signature, F_S) \ diff --git a/src/hotspot/share/code/compiledIC.cpp b/src/hotspot/share/code/compiledIC.cpp index 079c8199b1870..f142e306a6b02 100644 --- a/src/hotspot/share/code/compiledIC.cpp +++ b/src/hotspot/share/code/compiledIC.cpp @@ -83,6 +83,7 @@ void CompiledICData::initialize(CallInfo* call_info, Klass* receiver_klass) { _speculated_klass = (uintptr_t)receiver_klass; } if (call_info->call_kind() == CallInfo::itable_call) { + assert(call_info->resolved_method() != nullptr, "virtual or interface method must be found"); _itable_defc_klass = call_info->resolved_method()->method_holder(); _itable_refc_klass = call_info->resolved_klass(); } @@ -238,6 +239,7 @@ void CompiledIC::set_to_megamorphic(CallInfo* call_info) { return; } #ifdef ASSERT + assert(call_info->resolved_method() != nullptr, "virtual or interface method must be found"); int index = call_info->resolved_method()->itable_index(); assert(index == itable_index, "CallInfo pre-computes this"); InstanceKlass* k = call_info->resolved_method()->method_holder(); @@ -254,6 +256,7 @@ void CompiledIC::set_to_megamorphic(CallInfo* call_info) { } } + assert(call_info->selected_method() != nullptr, "virtual or interface method must be found"); log_trace(inlinecache)("IC@" INTPTR_FORMAT ": to megamorphic %s entry: " INTPTR_FORMAT, p2i(_call->instruction_address()), call_info->selected_method()->print_value_string(), p2i(entry)); diff --git a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp index 1cfd6fca08a6f..3f7fefd8a07a6 100644 --- a/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp +++ b/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp @@ -87,8 +87,6 @@ class G1ParScanThreadState : public CHeapObj { // Indicates whether in the last generation (old) there is no more space // available for allocation. bool _old_gen_is_full; - // Size (in elements) of a partial objArray task chunk. - size_t _partial_objarray_chunk_size; PartialArrayStateAllocator* _partial_array_state_allocator; PartialArrayTaskStepper _partial_array_stepper; StringDedup::Requests _string_dedup_requests; diff --git a/src/hotspot/share/gc/shared/oopStorage.cpp b/src/hotspot/share/gc/shared/oopStorage.cpp index 6c5e57c947952..568888ac7d97e 100644 --- a/src/hotspot/share/gc/shared/oopStorage.cpp +++ b/src/hotspot/share/gc/shared/oopStorage.cpp @@ -1135,6 +1135,26 @@ void OopStorage::BasicParState::report_num_dead() const { const char* OopStorage::name() const { return _name; } +bool OopStorage::print_containing(const oop* addr, outputStream* st) { + if (addr != nullptr) { + Block* block = find_block_or_null(addr); + if (block != nullptr && block->print_containing(addr, st)) { + st->print(" in oop storage \"%s\"", name()); + return true; + } + } + return false; +} + +bool OopStorage::Block::print_containing(const oop* addr, outputStream* st) { + if (contains(addr)) { + st->print(PTR_FORMAT " is a pointer %u/%zu into block %zu", + p2i(addr), get_index(addr), ARRAY_SIZE(_data), _active_index); + return true; + } + return false; +} + #ifndef PRODUCT void OopStorage::print_on(outputStream* st) const { diff --git a/src/hotspot/share/gc/shared/oopStorage.hpp b/src/hotspot/share/gc/shared/oopStorage.hpp index f78746fc14a27..96cc5a23d6a91 100644 --- a/src/hotspot/share/gc/shared/oopStorage.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.hpp @@ -213,6 +213,7 @@ class OopStorage : public CHeapObjBase { // Debugging and logging support. const char* name() const; void print_on(outputStream* st) const PRODUCT_RETURN; + bool print_containing(const oop* addr, outputStream* st); // Provides access to storage internals, for unit testing. // Declare, but not define, the public class OopStorage::TestAccess. diff --git a/src/hotspot/share/gc/shared/oopStorage.inline.hpp b/src/hotspot/share/gc/shared/oopStorage.inline.hpp index ce78e507efc12..545da0be0a76e 100644 --- a/src/hotspot/share/gc/shared/oopStorage.inline.hpp +++ b/src/hotspot/share/gc/shared/oopStorage.inline.hpp @@ -196,6 +196,8 @@ class OopStorage::Block /* No base class, to avoid messing up alignment. */ { template bool iterate(F f); template bool iterate(F f) const; + + bool print_containing(const oop* addr, outputStream* st); }; // class Block inline OopStorage::Block* OopStorage::AllocationList::head() { diff --git a/src/hotspot/share/gc/shared/oopStorageSet.cpp b/src/hotspot/share/gc/shared/oopStorageSet.cpp index d061fc7763868..c6947590d96fb 100644 --- a/src/hotspot/share/gc/shared/oopStorageSet.cpp +++ b/src/hotspot/share/gc/shared/oopStorageSet.cpp @@ -82,6 +82,23 @@ template OopStorage* OopStorageSet::get_storage(StrongId); template OopStorage* OopStorageSet::get_storage(WeakId); template OopStorage* OopStorageSet::get_storage(Id); +bool OopStorageSet::print_containing(const void* addr, outputStream* st) { + if (addr != nullptr) { + const void* aligned_addr = align_down(addr, alignof(oop)); + for (OopStorage* storage : Range()) { + if (storage->print_containing((oop*) aligned_addr, st)) { + if (aligned_addr != addr) { + st->print_cr(" (unaligned)"); + } else { + st->cr(); + } + return true; + } + } + } + return false; +} + #ifdef ASSERT void OopStorageSet::verify_initialized(uint index) { diff --git a/src/hotspot/share/gc/shared/oopStorageSet.hpp b/src/hotspot/share/gc/shared/oopStorageSet.hpp index 273a769dd59d4..867172c41ad74 100644 --- a/src/hotspot/share/gc/shared/oopStorageSet.hpp +++ b/src/hotspot/share/gc/shared/oopStorageSet.hpp @@ -26,6 +26,7 @@ #define SHARE_GC_SHARED_OOPSTORAGESET_HPP #include "nmt/memTag.hpp" +#include "oops/oop.hpp" #include "utilities/debug.hpp" #include "utilities/enumIterator.hpp" #include "utilities/globalDefinitions.hpp" @@ -89,6 +90,8 @@ class OopStorageSet : public AllStatic { template static void strong_oops_do(Closure* cl); + // Debugging: print location info, if in storage. + static bool print_containing(const void* addr, outputStream* st); }; ENUMERATOR_VALUE_RANGE(OopStorageSet::StrongId, diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp index 368d76696058c..71174d11a6214 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.cpp @@ -271,6 +271,11 @@ bool ShenandoahBarrierSetC2::is_shenandoah_wb_pre_call(Node* call) { call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::write_ref_field_pre_entry); } +bool ShenandoahBarrierSetC2::is_shenandoah_clone_call(Node* call) { + return call->is_CallLeaf() && + call->as_CallLeaf()->entry_point() == CAST_FROM_FN_PTR(address, ShenandoahRuntime::shenandoah_clone_barrier); +} + bool ShenandoahBarrierSetC2::is_shenandoah_lrb_call(Node* call) { if (!call->is_CallLeaf()) { return false; @@ -675,20 +680,10 @@ bool ShenandoahBarrierSetC2::is_gc_pre_barrier_node(Node* node) const { return is_shenandoah_wb_pre_call(node); } -// Support for GC barriers emitted during parsing bool ShenandoahBarrierSetC2::is_gc_barrier_node(Node* node) const { - if (node->Opcode() == Op_ShenandoahLoadReferenceBarrier) return true; - if (node->Opcode() != Op_CallLeaf && node->Opcode() != Op_CallLeafNoFP) { - return false; - } - CallLeafNode *call = node->as_CallLeaf(); - if (call->_name == nullptr) { - return false; - } - - return strcmp(call->_name, "shenandoah_clone_barrier") == 0 || - strcmp(call->_name, "shenandoah_cas_obj") == 0 || - strcmp(call->_name, "shenandoah_wb_pre") == 0; + return is_shenandoah_lrb_call(node) || + is_shenandoah_wb_pre_call(node) || + is_shenandoah_clone_call(node); } Node* ShenandoahBarrierSetC2::step_over_gc_barrier(Node* c) const { diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp index 4619b217e96c6..cbfacea31ab7a 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahBarrierSetC2.hpp @@ -85,6 +85,7 @@ class ShenandoahBarrierSetC2 : public BarrierSetC2 { static ShenandoahBarrierSetC2* bsc2(); static bool is_shenandoah_wb_pre_call(Node* call); + static bool is_shenandoah_clone_call(Node* call); static bool is_shenandoah_lrb_call(Node* call); static bool is_shenandoah_marking_if(PhaseValues* phase, Node* n); static bool is_shenandoah_state_load(Node* n); diff --git a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp index 0a51f74299545..7526f895f2f7f 100644 --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp @@ -414,7 +414,7 @@ void ShenandoahBarrierC2Support::verify(RootNode* root) { "cipherBlockChaining_decryptAESCrypt", { { TypeFunc::Parms, ShenandoahLoad }, { TypeFunc::Parms+1, ShenandoahStore }, { TypeFunc::Parms+2, ShenandoahLoad }, { TypeFunc::Parms+3, ShenandoahLoad }, { -1, ShenandoahNone}, { -1, ShenandoahNone} }, - "shenandoah_clone_barrier", + "shenandoah_clone", { { TypeFunc::Parms, ShenandoahLoad }, { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone}, { -1, ShenandoahNone} }, "ghash_processBlocks", diff --git a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp index 6ed75a9d96106..75cdb99e177d1 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahConcurrentMark.cpp @@ -225,8 +225,7 @@ void ShenandoahConcurrentMark::finish_mark() { assert(Thread::current()->is_VM_thread(), "Must by VM Thread"); finish_mark_work(); assert(task_queues()->is_empty(), "Should be empty"); - TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); - TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(task_queues()->print_and_reset_taskqueue_stats("")); ShenandoahHeap* const heap = ShenandoahHeap::heap(); heap->set_concurrent_mark_in_progress(false); diff --git a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp index 95a70de5790e9..8a4ef63b8e38b 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahControlThread.cpp @@ -371,6 +371,16 @@ void ShenandoahControlThread::request_gc(GCCause::Cause cause) { } void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { + // For normal requested GCs (System.gc) we want to block the caller. However, + // for whitebox requested GC, we want to initiate the GC and return immediately. + // The whitebox caller thread will arrange for itself to wait until the GC notifies + // it that has reached the requested breakpoint (phase in the GC). + if (cause == GCCause::_wb_breakpoint) { + _requested_gc_cause = cause; + _gc_requested.set(); + return; + } + // Make sure we have at least one complete GC cycle before unblocking // from the explicit GC request. // @@ -390,9 +400,7 @@ void ShenandoahControlThread::handle_requested_gc(GCCause::Cause cause) { _requested_gc_cause = cause; _gc_requested.set(); - if (cause != GCCause::_wb_breakpoint) { - ml.wait(); - } + ml.wait(); current_gc_id = get_gc_id(); } } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp index 05cd8ef66b9d1..9a30b1fed8724 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahSTWMark.cpp @@ -133,8 +133,7 @@ void ShenandoahSTWMark::mark() { ShenandoahCodeRoots::disarm_nmethods(); assert(task_queues()->is_empty(), "Should be empty"); - TASKQUEUE_STATS_ONLY(task_queues()->print_taskqueue_stats()); - TASKQUEUE_STATS_ONLY(task_queues()->reset_taskqueue_stats()); + TASKQUEUE_STATS_ONLY(task_queues()->print_and_reset_taskqueue_stats("")); } void ShenandoahSTWMark::mark_roots(uint worker_id) { diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp index 3cddc0c6c0a83..eb185c197bd5d 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.cpp @@ -51,45 +51,6 @@ bool ShenandoahObjToScanQueueSet::is_empty() { return true; } -#if TASKQUEUE_STATS -void ShenandoahObjToScanQueueSet::print_taskqueue_stats_hdr(outputStream* const st) { - st->print_raw_cr("GC Task Stats"); - st->print_raw("thr "); TaskQueueStats::print_header(1, st); st->cr(); - st->print_raw("--- "); TaskQueueStats::print_header(2, st); st->cr(); -} - -void ShenandoahObjToScanQueueSet::print_taskqueue_stats() const { - if (!log_develop_is_enabled(Trace, gc, task, stats)) { - return; - } - Log(gc, task, stats) log; - ResourceMark rm; - LogStream ls(log.trace()); - outputStream* st = &ls; - print_taskqueue_stats_hdr(st); - - ShenandoahObjToScanQueueSet* queues = const_cast(this); - TaskQueueStats totals; - const uint n = size(); - for (uint i = 0; i < n; ++i) { - st->print(UINT32_FORMAT_W(3), i); - queues->queue(i)->stats.print(st); - st->cr(); - totals += queues->queue(i)->stats; - } - st->print("tot "); totals.print(st); st->cr(); - DEBUG_ONLY(totals.verify()); - -} - -void ShenandoahObjToScanQueueSet::reset_taskqueue_stats() { - const uint n = size(); - for (uint i = 0; i < n; ++i) { - queue(i)->stats.reset(); - } -} -#endif // TASKQUEUE_STATS - bool ShenandoahTerminatorTerminator::should_exit_termination() { return _heap->cancelled_gc(); } diff --git a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp index 2b160a2938794..10887ad8c19d6 100644 --- a/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahTaskqueue.hpp @@ -355,12 +355,6 @@ class ShenandoahObjToScanQueueSet: public ParallelClaimableQueueSet +template class ZArenaHashtable : public ResourceObj { class ZArenaHashtableEntry : public ResourceObj { public: @@ -55,10 +55,10 @@ class ZArenaHashtable : public ResourceObj { V _value; }; - static const size_t _table_mask = _table_size - 1; + static const size_t TableMask = TableSize - 1; Arena* _arena; - ZArenaHashtableEntry* _table[_table_size]; + ZArenaHashtableEntry* _table[TableSize]; public: class Iterator { @@ -84,7 +84,7 @@ class ZArenaHashtable : public ResourceObj { if (_current_entry != nullptr) { _current_entry = _current_entry->_next; } - while (_current_entry == nullptr && ++_current_index < _table_size) { + while (_current_entry == nullptr && ++_current_index < TableSize) { _current_entry = _table->_table[_current_index]; } } @@ -100,12 +100,12 @@ class ZArenaHashtable : public ResourceObj { ZArenaHashtableEntry* entry = new (_arena) ZArenaHashtableEntry(); entry->_key = key; entry->_value = value; - entry->_next = _table[key & _table_mask]; - _table[key & _table_mask] = entry; + entry->_next = _table[key & TableMask]; + _table[key & TableMask] = entry; } V* get(K key) const { - for (ZArenaHashtableEntry* e = _table[key & _table_mask]; e != nullptr; e = e->_next) { + for (ZArenaHashtableEntry* e = _table[key & TableMask]; e != nullptr; e = e->_next) { if (e->_key == key) { return &(e->_value); } diff --git a/src/hotspot/share/gc/z/zBarrierSet.hpp b/src/hotspot/share/gc/z/zBarrierSet.hpp index bf233df683afb..9c20211e2285d 100644 --- a/src/hotspot/share/gc/z/zBarrierSet.hpp +++ b/src/hotspot/share/gc/z/zBarrierSet.hpp @@ -155,7 +155,7 @@ class ZBarrierSet : public BarrierSet { }; template<> struct BarrierSet::GetName { - static const BarrierSet::Name value = BarrierSet::ZBarrierSet; + static const BarrierSet::Name Value = BarrierSet::ZBarrierSet; }; template<> struct BarrierSet::GetType { diff --git a/src/hotspot/share/gc/z/zDirector.cpp b/src/hotspot/share/gc/z/zDirector.cpp index 8901a9fbc6500..481525c425af0 100644 --- a/src/hotspot/share/gc/z/zDirector.cpp +++ b/src/hotspot/share/gc/z/zDirector.cpp @@ -839,7 +839,7 @@ void ZDirector::evaluate_rules() { } bool ZDirector::wait_for_tick() { - const uint64_t interval_ms = MILLIUNITS / decision_hz; + const uint64_t interval_ms = MILLIUNITS / DecisionHz; ZLocker locker(&_monitor); diff --git a/src/hotspot/share/gc/z/zDirector.hpp b/src/hotspot/share/gc/z/zDirector.hpp index 73c556a2fbd46..929ec6c2c566b 100644 --- a/src/hotspot/share/gc/z/zDirector.hpp +++ b/src/hotspot/share/gc/z/zDirector.hpp @@ -29,7 +29,7 @@ class ZDirector : public ZThread { private: - static const uint64_t decision_hz = 100; + static const uint64_t DecisionHz = 100; static ZDirector* _director; ZConditionLock _monitor; diff --git a/src/hotspot/share/gc/z/zHeap.cpp b/src/hotspot/share/gc/z/zHeap.cpp index 21ff703796219..dc5f1e3d21d57 100644 --- a/src/hotspot/share/gc/z/zHeap.cpp +++ b/src/hotspot/share/gc/z/zHeap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -248,8 +248,7 @@ void ZHeap::free_page(ZPage* page) { _page_table.remove(page); if (page->is_old()) { - page->verify_remset_cleared_current(); - page->verify_remset_cleared_previous(); + page->remset_delete(); } // Free page @@ -261,12 +260,10 @@ size_t ZHeap::free_empty_pages(const ZArray* pages) { // Remove page table entries ZArrayIterator iter(pages); for (ZPage* page; iter.next(&page);) { + _page_table.remove(page); if (page->is_old()) { - // The remset of pages should be clean when installed into the page - // cache. - page->remset_clear(); + page->remset_delete(); } - _page_table.remove(page); freed += page->size(); } diff --git a/src/hotspot/share/gc/z/zLiveMap.cpp b/src/hotspot/share/gc/z/zLiveMap.cpp index 4123620f8b7e0..715ebc6291724 100644 --- a/src/hotspot/share/gc/z/zLiveMap.cpp +++ b/src/hotspot/share/gc/z/zLiveMap.cpp @@ -35,9 +35,9 @@ static const ZStatCounter ZCounterMarkSeqNumResetContention("Contention", "Mark SeqNum Reset Contention", ZStatUnitOpsPerSecond); static const ZStatCounter ZCounterMarkSegmentResetContention("Contention", "Mark Segment Reset Contention", ZStatUnitOpsPerSecond); -static size_t bitmap_size(uint32_t size, size_t nsegments) { +static size_t bitmap_size(uint32_t size, size_t NumSegments) { // We need at least one bit per segment - return MAX2(size, nsegments) * 2; + return MAX2(size, NumSegments) * 2; } ZLiveMap::ZLiveMap(uint32_t size) @@ -46,7 +46,7 @@ ZLiveMap::ZLiveMap(uint32_t size) _live_bytes(0), _segment_live_bits(0), _segment_claim_bits(0), - _bitmap(bitmap_size(size, nsegments)), + _bitmap(bitmap_size(size, NumSegments)), _segment_shift(log2i_exact(segment_size())) {} void ZLiveMap::reset(ZGenerationId id) { @@ -127,7 +127,7 @@ void ZLiveMap::reset_segment(BitMap::idx_t segment) { } void ZLiveMap::resize(uint32_t size) { - const size_t new_bitmap_size = bitmap_size(size, nsegments); + const size_t new_bitmap_size = bitmap_size(size, NumSegments); if (_bitmap.size() != new_bitmap_size) { _bitmap.reinitialize(new_bitmap_size, false /* clear */); _segment_shift = log2i_exact(segment_size()); diff --git a/src/hotspot/share/gc/z/zLiveMap.hpp b/src/hotspot/share/gc/z/zLiveMap.hpp index f8b16d06dc52c..7c18e1db06096 100644 --- a/src/hotspot/share/gc/z/zLiveMap.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.hpp @@ -35,7 +35,7 @@ class ZLiveMap { friend class ZLiveMapTest; private: - static const size_t nsegments = 64; + static const size_t NumSegments = 64; volatile uint32_t _seqnum; volatile uint32_t _live_objects; diff --git a/src/hotspot/share/gc/z/zLiveMap.inline.hpp b/src/hotspot/share/gc/z/zLiveMap.inline.hpp index 28390b72a89ca..a9382522480c0 100644 --- a/src/hotspot/share/gc/z/zLiveMap.inline.hpp +++ b/src/hotspot/share/gc/z/zLiveMap.inline.hpp @@ -52,19 +52,19 @@ inline size_t ZLiveMap::live_bytes() const { } inline const BitMapView ZLiveMap::segment_live_bits() const { - return BitMapView(const_cast(&_segment_live_bits), nsegments); + return BitMapView(const_cast(&_segment_live_bits), NumSegments); } inline const BitMapView ZLiveMap::segment_claim_bits() const { - return BitMapView(const_cast(&_segment_claim_bits), nsegments); + return BitMapView(const_cast(&_segment_claim_bits), NumSegments); } inline BitMapView ZLiveMap::segment_live_bits() { - return BitMapView(&_segment_live_bits, nsegments); + return BitMapView(&_segment_live_bits, NumSegments); } inline BitMapView ZLiveMap::segment_claim_bits() { - return BitMapView(&_segment_claim_bits, nsegments); + return BitMapView(&_segment_claim_bits, NumSegments); } inline bool ZLiveMap::is_segment_live(BitMap::idx_t segment) const { @@ -80,15 +80,15 @@ inline bool ZLiveMap::claim_segment(BitMap::idx_t segment) { } inline BitMap::idx_t ZLiveMap::first_live_segment() const { - return segment_live_bits().find_first_set_bit(0, nsegments); + return segment_live_bits().find_first_set_bit(0, NumSegments); } inline BitMap::idx_t ZLiveMap::next_live_segment(BitMap::idx_t segment) const { - return segment_live_bits().find_first_set_bit(segment + 1, nsegments); + return segment_live_bits().find_first_set_bit(segment + 1, NumSegments); } inline BitMap::idx_t ZLiveMap::segment_size() const { - return _bitmap.size() / nsegments; + return _bitmap.size() / NumSegments; } inline BitMap::idx_t ZLiveMap::index_to_segment(BitMap::idx_t index) const { @@ -167,7 +167,7 @@ inline void ZLiveMap::iterate(ZGenerationId id, Function function) { return true; }; - for (BitMap::idx_t segment = first_live_segment(); segment < nsegments; segment = next_live_segment(segment)) { + for (BitMap::idx_t segment = first_live_segment(); segment < NumSegments; segment = next_live_segment(segment)) { // For each live segment iterate_segment(segment, live_only); } diff --git a/src/hotspot/share/gc/z/zPage.cpp b/src/hotspot/share/gc/z/zPage.cpp index dc40c5367c121..ff56768e9ad99 100644 --- a/src/hotspot/share/gc/z/zPage.cpp +++ b/src/hotspot/share/gc/z/zPage.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -78,27 +78,16 @@ void ZPage::reset_seqnum() { Atomic::store(&_seqnum_other, ZGeneration::generation(_generation_id == ZGenerationId::young ? ZGenerationId::old : ZGenerationId::young)->seqnum()); } -void ZPage::remset_initialize() { - // Remsets should only be initialized once and only for old pages. +void ZPage::remset_alloc() { + // Remsets should only be allocated/initialized once and only for old pages. assert(!_remembered_set.is_initialized(), "Should not be initialized"); assert(is_old(), "Only old pages need a remset"); _remembered_set.initialize(size()); } -void ZPage::remset_initialize_or_verify_cleared() { - assert(is_old(), "Only old pages need a remset"); - - if (_remembered_set.is_initialized()) { - verify_remset_cleared_current(); - verify_remset_cleared_previous(); - } else { - remset_initialize(); - } -} - -void ZPage::remset_clear() { - _remembered_set.clear_all(); +void ZPage::remset_delete() { + _remembered_set.delete_all(); } void ZPage::reset(ZPageAge age) { @@ -123,7 +112,6 @@ void ZPage::reset_top_for_allocation() { void ZPage::reset_type_and_size(ZPageType type) { _type = type; _livemap.resize(object_max_count()); - _remembered_set.resize(size()); } ZPage* ZPage::retype(ZPageType type) { @@ -216,10 +204,6 @@ void ZPage::verify_remset_cleared_previous() const { } } -void ZPage::clear_remset_current() { - _remembered_set.clear_current(); -} - void ZPage::clear_remset_previous() { _remembered_set.clear_previous(); } diff --git a/src/hotspot/share/gc/z/zPage.hpp b/src/hotspot/share/gc/z/zPage.hpp index 42e14f904bc77..9b6c155f77d9f 100644 --- a/src/hotspot/share/gc/z/zPage.hpp +++ b/src/hotspot/share/gc/z/zPage.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -155,9 +155,8 @@ class ZPage : public CHeapObj { void clear_remset_range_non_par_current(uintptr_t l_offset, size_t size); void swap_remset_bitmaps(); - void remset_initialize(); - void remset_initialize_or_verify_cleared(); - void remset_clear(); + void remset_alloc(); + void remset_delete(); ZBitMap::ReverseIterator remset_reverse_iterator_previous(); BitMap::Iterator remset_iterator_limited_current(uintptr_t l_offset, size_t size); @@ -182,7 +181,6 @@ class ZPage : public CHeapObj { void verify_remset_cleared_current() const; void verify_remset_cleared_previous() const; - void clear_remset_current(); void clear_remset_previous(); void* remset_current(); diff --git a/src/hotspot/share/gc/z/zPageAllocator.cpp b/src/hotspot/share/gc/z/zPageAllocator.cpp index f5d8ae6e3d160..01200f76b519e 100644 --- a/src/hotspot/share/gc/z/zPageAllocator.cpp +++ b/src/hotspot/share/gc/z/zPageAllocator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2015, 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 @@ -733,7 +733,7 @@ ZPage* ZPageAllocator::alloc_page(ZPageType type, size_t size, ZAllocationFlags page->reset_top_for_allocation(); page->reset_livemap(); if (age == ZPageAge::old) { - page->remset_initialize_or_verify_cleared(); + page->remset_alloc(); } // Update allocation statistics. Exclude gc relocations to avoid diff --git a/src/hotspot/share/gc/z/zReferenceProcessor.hpp b/src/hotspot/share/gc/z/zReferenceProcessor.hpp index f8e924ed99fc1..31c789ee859e5 100644 --- a/src/hotspot/share/gc/z/zReferenceProcessor.hpp +++ b/src/hotspot/share/gc/z/zReferenceProcessor.hpp @@ -36,8 +36,8 @@ class ZReferenceProcessor : public ReferenceDiscoverer { friend class ZReferenceProcessorTask; private: - static const size_t reference_type_count = REF_PHANTOM + 1; - typedef size_t Counters[reference_type_count]; + static const size_t ReferenceTypeCount = REF_PHANTOM + 1; + typedef size_t Counters[ReferenceTypeCount]; ZWorkers* const _workers; ReferencePolicy* _soft_reference_policy; diff --git a/src/hotspot/share/gc/z/zRelocate.cpp b/src/hotspot/share/gc/z/zRelocate.cpp index 90209e4c62253..33304bcefd37f 100644 --- a/src/hotspot/share/gc/z/zRelocate.cpp +++ b/src/hotspot/share/gc/z/zRelocate.cpp @@ -848,7 +848,7 @@ class ZRelocateWork : public StackObj { to_page->reset(to_age); to_page->reset_top_for_allocation(); if (promotion) { - to_page->remset_initialize(); + to_page->remset_alloc(); } // Verify that the inactive remset is clear when resetting the page for @@ -943,35 +943,15 @@ class ZRelocateWork : public StackObj { return ZGeneration::old()->active_remset_is_current(); } - void clear_remset_before_reuse(ZPage* page, bool in_place) { + void clear_remset_before_in_place_reuse(ZPage* page) { if (_forwarding->from_age() != ZPageAge::old) { // No remset bits return; } - if (in_place) { - // Clear 'previous' remset bits. For in-place relocated pages, the previous - // remset bits are always used, even when active_remset_is_current(). - page->clear_remset_previous(); - - return; - } - - // Normal relocate - - // Clear active remset bits - if (active_remset_is_current()) { - page->clear_remset_current(); - } else { - page->clear_remset_previous(); - } - - // Verify that inactive remset bits are all cleared - if (active_remset_is_current()) { - page->verify_remset_cleared_previous(); - } else { - page->verify_remset_cleared_current(); - } + // Clear 'previous' remset bits. For in-place relocated pages, the previous + // remset bits are always used, even when active_remset_is_current(). + page->clear_remset_previous(); } void finish_in_place_relocation() { @@ -1017,7 +997,7 @@ class ZRelocateWork : public StackObj { ZPage* const page = _forwarding->detach_page(); // Ensure that previous remset bits are cleared - clear_remset_before_reuse(page, true /* in_place */); + clear_remset_before_in_place_reuse(page); page->log_msg(" (relocate page done in-place)"); @@ -1029,11 +1009,6 @@ class ZRelocateWork : public StackObj { // Wait for all other threads to call release_page ZPage* const page = _forwarding->detach_page(); - // Ensure that all remset bits are cleared - // Note: cleared after detach_page, when we know that - // the young generation isn't scanning the remset. - clear_remset_before_reuse(page, false /* in_place */); - page->log_msg(" (relocate page done normal)"); // Free page @@ -1292,7 +1267,7 @@ class ZFlipAgePagesTask : public ZTask { new_page->reset(to_age); new_page->reset_livemap(); if (promotion) { - new_page->remset_initialize(); + new_page->remset_alloc(); } if (promotion) { diff --git a/src/hotspot/share/gc/z/zRememberedSet.cpp b/src/hotspot/share/gc/z/zRememberedSet.cpp index ed1dcfaf14d55..f605401648dfb 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.cpp +++ b/src/hotspot/share/gc/z/zRememberedSet.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -55,18 +55,10 @@ void ZRememberedSet::initialize(size_t page_size) { _bitmap[1].initialize(size_in_bits, true /* clear */); } -void ZRememberedSet::resize(size_t page_size) { - // The bitmaps only need to be resized if remset has been - // initialized, and hence the bitmaps have been initialized. - if (is_initialized()) { - const BitMap::idx_t size_in_bits = to_bit_size(page_size); - - // The bitmaps need to be cleared when free, but since this function is - // only used for shrinking the clear argument is correct but not crucial. - assert(size_in_bits <= _bitmap[0].size(), "Only used for shrinking"); - _bitmap[0].resize(size_in_bits, true /* clear */); - _bitmap[1].resize(size_in_bits, true /* clear */); - } +void ZRememberedSet::delete_all() { + assert(is_initialized(), "precondition"); + _bitmap[0].resize(0); + _bitmap[1].resize(0); } bool ZRememberedSet::is_cleared_current() const { @@ -77,15 +69,6 @@ bool ZRememberedSet::is_cleared_previous() const { return previous()->is_empty(); } -void ZRememberedSet::clear_all() { - _bitmap[0].clear_large(); - _bitmap[1].clear_large(); -} - -void ZRememberedSet::clear_current() { - current()->clear_large(); -} - void ZRememberedSet::clear_previous() { previous()->clear_large(); } diff --git a/src/hotspot/share/gc/z/zRememberedSet.hpp b/src/hotspot/share/gc/z/zRememberedSet.hpp index d18c357f0ddbe..c3c6e8bc31317 100644 --- a/src/hotspot/share/gc/z/zRememberedSet.hpp +++ b/src/hotspot/share/gc/z/zRememberedSet.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -114,8 +114,7 @@ class ZRememberedSet { bool is_initialized() const; void initialize(size_t page_size); - - void resize(size_t page_size); + void delete_all(); bool at_current(uintptr_t offset) const; bool at_previous(uintptr_t offset) const; @@ -133,8 +132,6 @@ class ZRememberedSet { bool is_cleared_current() const; bool is_cleared_previous() const; - void clear_all(); - void clear_current(); void clear_previous(); void swap_remset_bitmaps(); diff --git a/src/hotspot/share/gc/z/zStackWatermark.cpp b/src/hotspot/share/gc/z/zStackWatermark.cpp index ead5300e9c318..0c7ec553e5c0c 100644 --- a/src/hotspot/share/gc/z/zStackWatermark.cpp +++ b/src/hotspot/share/gc/z/zStackWatermark.cpp @@ -130,7 +130,7 @@ void ZStackWatermark::save_old_watermark() { } else { // Found none too replace - push it to the top _old_watermarks_newest++; - assert(_old_watermarks_newest < _old_watermarks_max, "Unexpected amount of old watermarks"); + assert(_old_watermarks_newest < OldWatermarksMax, "Unexpected amount of old watermarks"); } // Install old watermark diff --git a/src/hotspot/share/gc/z/zStackWatermark.hpp b/src/hotspot/share/gc/z/zStackWatermark.hpp index fd4efeef76131..f2cf59d3b4a80 100644 --- a/src/hotspot/share/gc/z/zStackWatermark.hpp +++ b/src/hotspot/share/gc/z/zStackWatermark.hpp @@ -59,8 +59,8 @@ class ZStackWatermark : public StackWatermark { private: // Stores old watermarks, which describes the // colors of the non-processed part of the stack. - const static int _old_watermarks_max = 3; - ZColorWatermark _old_watermarks[_old_watermarks_max]; + static const int OldWatermarksMax = 3; + ZColorWatermark _old_watermarks[OldWatermarksMax]; int _old_watermarks_newest; ThreadLocalAllocStats _stats; diff --git a/src/hotspot/share/gc/z/zStat.cpp b/src/hotspot/share/gc/z/zStat.cpp index c2a7a23c04f53..56b3590960f7c 100644 --- a/src/hotspot/share/gc/z/zStat.cpp +++ b/src/hotspot/share/gc/z/zStat.cpp @@ -1019,7 +1019,7 @@ ZStatMutatorAllocRateStats ZStatMutatorAllocRate::stats() { // Stat thread // ZStat::ZStat() - : _metronome(sample_hz) { + : _metronome(SampleHz) { set_name("ZStat"); create_and_start(); ZStatMutatorAllocRate::initialize(); @@ -1098,11 +1098,11 @@ void ZStat::terminate() { // class ZStatTablePrinter { private: - static const size_t _buffer_size = 256; + static const size_t BufferSize = 256; const size_t _column0_width; const size_t _columnN_width; - char _buffer[_buffer_size]; + char _buffer[BufferSize]; public: class ZColumn { @@ -1119,7 +1119,7 @@ class ZStatTablePrinter { } size_t print(size_t position, const char* fmt, va_list va) { - const int res = jio_vsnprintf(_buffer + position, _buffer_size - position, fmt, va); + const int res = jio_vsnprintf(_buffer + position, BufferSize - position, fmt, va); if (res < 0) { return 0; } diff --git a/src/hotspot/share/gc/z/zStat.hpp b/src/hotspot/share/gc/z/zStat.hpp index d7482dbe6aaaf..d7fff6d7b8e13 100644 --- a/src/hotspot/share/gc/z/zStat.hpp +++ b/src/hotspot/share/gc/z/zStat.hpp @@ -384,7 +384,7 @@ class ZStatMutatorAllocRate : public AllStatic { // class ZStat : public ZThread { private: - static const uint64_t sample_hz = 1; + static const uint64_t SampleHz = 1; ZMetronome _metronome; diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp index c94551dc62d20..78106aad729b7 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.cpp @@ -55,7 +55,7 @@ ZStoreBarrierBuffer::ZStoreBarrierBuffer() _last_installed_color(), _base_pointer_lock(), _base_pointers(), - _current(ZBufferStoreBarriers ? _buffer_size_bytes : 0) {} + _current(ZBufferStoreBarriers ? BufferSizeBytes : 0) {} void ZStoreBarrierBuffer::initialize() { _last_processed_color = ZPointerStoreGoodMask; @@ -63,11 +63,11 @@ void ZStoreBarrierBuffer::initialize() { } void ZStoreBarrierBuffer::clear() { - _current = _buffer_size_bytes; + _current = BufferSizeBytes; } bool ZStoreBarrierBuffer::is_empty() const { - return _current == _buffer_size_bytes; + return _current == BufferSizeBytes; } void ZStoreBarrierBuffer::install_base_pointers_inner() { @@ -79,7 +79,7 @@ void ZStoreBarrierBuffer::install_base_pointers_inner() { (ZPointer::remap_bits(_last_processed_color) & ZPointerRemappedOldMask) == 0, "Should not have double bit errors"); - for (size_t i = current(); i < _buffer_length; ++i) { + for (size_t i = current(); i < BufferLength; ++i) { const ZStoreBarrierEntry& entry = _buffer[i]; volatile zpointer* const p = entry._p; const zaddress_unsafe p_unsafe = to_zaddress_unsafe((uintptr_t)p); @@ -229,7 +229,7 @@ void ZStoreBarrierBuffer::on_new_phase() { // Install all base pointers for relocation install_base_pointers(); - for (size_t i = current(); i < _buffer_length; ++i) { + for (size_t i = current(); i < BufferLength; ++i) { on_new_phase_relocate(i); on_new_phase_remember(i); on_new_phase_mark(i); @@ -259,7 +259,7 @@ void ZStoreBarrierBuffer::on_error(outputStream* st) { st->print_cr(" _last_processed_color: " PTR_FORMAT, _last_processed_color); st->print_cr(" _last_installed_color: " PTR_FORMAT, _last_installed_color); - for (size_t i = current(); i < _buffer_length; ++i) { + for (size_t i = current(); i < BufferLength; ++i) { st->print_cr(" [%2zu]: base: " PTR_FORMAT " p: " PTR_FORMAT " prev: " PTR_FORMAT, i, untype(_base_pointers[i]), @@ -276,7 +276,7 @@ void ZStoreBarrierBuffer::flush() { OnError on_error(this); VMErrorCallbackMark mark(&on_error); - for (size_t i = current(); i < _buffer_length; ++i) { + for (size_t i = current(); i < BufferLength; ++i) { const ZStoreBarrierEntry& entry = _buffer[i]; const zaddress addr = ZBarrier::make_load_good(entry._prev); ZBarrier::mark_and_remember(entry._p, addr); @@ -296,7 +296,7 @@ bool ZStoreBarrierBuffer::is_in(volatile zpointer* p) { const uintptr_t last_remap_bits = ZPointer::remap_bits(buffer->_last_processed_color) & ZPointerRemappedMask; const bool needs_remap = last_remap_bits != ZPointerRemapped; - for (size_t i = buffer->current(); i < _buffer_length; ++i) { + for (size_t i = buffer->current(); i < BufferLength; ++i) { const ZStoreBarrierEntry& entry = buffer->_buffer[i]; volatile zpointer* entry_p = entry._p; diff --git a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp index f828ffb8ab25d..f2e4a343d9c01 100644 --- a/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp +++ b/src/hotspot/share/gc/z/zStoreBarrierBuffer.hpp @@ -50,10 +50,10 @@ class ZStoreBarrierBuffer : public CHeapObj { private: // Tune ZStoreBarrierBuffer length to decrease the opportunity goto // copy_store_at slow-path. - static const size_t _buffer_length = 32 LOONGARCH64_ONLY(+32); - static const size_t _buffer_size_bytes = _buffer_length * sizeof(ZStoreBarrierEntry); + static const size_t BufferLength = 32 LOONGARCH64_ONLY(+32); + static const size_t BufferSizeBytes = BufferLength * sizeof(ZStoreBarrierEntry); - ZStoreBarrierEntry _buffer[_buffer_length]; + ZStoreBarrierEntry _buffer[BufferLength]; // Color from previous phase this buffer was processed uintptr_t _last_processed_color; @@ -62,7 +62,7 @@ class ZStoreBarrierBuffer : public CHeapObj { uintptr_t _last_installed_color; ZLock _base_pointer_lock; - zaddress_unsafe _base_pointers[_buffer_length]; + zaddress_unsafe _base_pointers[BufferLength]; // sizeof(ZStoreBarrierEntry) scaled index growing downwards size_t _current; diff --git a/src/hotspot/share/gc/z/zValue.hpp b/src/hotspot/share/gc/z/zValue.hpp index 29f1b707e7c6b..4953978297f52 100644 --- a/src/hotspot/share/gc/z/zValue.hpp +++ b/src/hotspot/share/gc/z/zValue.hpp @@ -39,7 +39,7 @@ class ZValueStorage : public AllStatic { static uintptr_t _end; public: - static const size_t offset = 4 * K; + static const size_t Offset = 4 * K; static uintptr_t alloc(size_t size); }; diff --git a/src/hotspot/share/gc/z/zValue.inline.hpp b/src/hotspot/share/gc/z/zValue.inline.hpp index 2367bac0f0aab..c2aa8bbbb4004 100644 --- a/src/hotspot/share/gc/z/zValue.inline.hpp +++ b/src/hotspot/share/gc/z/zValue.inline.hpp @@ -44,7 +44,7 @@ template uintptr_t ZValueStorage::_top = 0; template uintptr_t ZValueStorage::alloc(size_t size) { - assert(size <= offset, "Allocation too large"); + assert(size <= Offset, "Allocation too large"); // Allocate entry in existing memory block const uintptr_t addr = align_up(_top, S::alignment()); @@ -56,10 +56,10 @@ uintptr_t ZValueStorage::alloc(size_t size) { } // Allocate new block of memory - const size_t block_alignment = offset; - const size_t block_size = offset * S::count(); + const size_t block_alignment = Offset; + const size_t block_size = Offset * S::count(); _top = ZUtils::alloc_aligned_unfreeable(block_alignment, block_size); - _end = _top + offset; + _end = _top + Offset; // Retry allocation return alloc(size); @@ -119,7 +119,7 @@ inline uint32_t ZPerWorkerStorage::id() { template inline uintptr_t ZValue::value_addr(uint32_t value_id) const { - return _addr + (value_id * S::offset); + return _addr + (value_id * S::Offset); } template diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp index b735965e9d49b..03b50e110e4c4 100644 --- a/src/hotspot/share/gc/z/zVerify.cpp +++ b/src/hotspot/share/gc/z/zVerify.cpp @@ -589,7 +589,7 @@ void ZVerify::on_color_flip() { for (JavaThreadIteratorWithHandle jtiwh; JavaThread* const jt = jtiwh.next(); ) { const ZStoreBarrierBuffer* const buffer = ZThreadLocalData::store_barrier_buffer(jt); - for (size_t i = buffer->current(); i < ZStoreBarrierBuffer::_buffer_length; ++i) { + for (size_t i = buffer->current(); i < ZStoreBarrierBuffer::BufferLength; ++i) { volatile zpointer* const p = buffer->_buffer[i]._p; bool created = false; z_verify_store_barrier_buffer_table->put_if_absent(p, true, &created); diff --git a/src/hotspot/share/interpreter/abstractInterpreter.cpp b/src/hotspot/share/interpreter/abstractInterpreter.cpp index 2fad5ba39ef5c..9d72f9ba0edec 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.cpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.cpp @@ -138,6 +138,7 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(const methodHan case vmIntrinsics::_dsin: return java_lang_math_sin; case vmIntrinsics::_dcos: return java_lang_math_cos; case vmIntrinsics::_dtan: return java_lang_math_tan; + case vmIntrinsics::_dtanh: return java_lang_math_tanh; case vmIntrinsics::_dabs: return java_lang_math_abs; case vmIntrinsics::_dlog: return java_lang_math_log; case vmIntrinsics::_dlog10: return java_lang_math_log10; @@ -198,6 +199,7 @@ vmIntrinsics::ID AbstractInterpreter::method_intrinsic(MethodKind kind) { case java_lang_math_sin : return vmIntrinsics::_dsin; case java_lang_math_cos : return vmIntrinsics::_dcos; case java_lang_math_tan : return vmIntrinsics::_dtan; + case java_lang_math_tanh : return vmIntrinsics::_dtanh; case java_lang_math_abs : return vmIntrinsics::_dabs; case java_lang_math_log : return vmIntrinsics::_dlog; case java_lang_math_log10 : return vmIntrinsics::_dlog10; @@ -309,6 +311,7 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) { case java_lang_math_sin : tty->print("java_lang_math_sin" ); break; case java_lang_math_cos : tty->print("java_lang_math_cos" ); break; case java_lang_math_tan : tty->print("java_lang_math_tan" ); break; + case java_lang_math_tanh : tty->print("java_lang_math_tanh" ); break; case java_lang_math_abs : tty->print("java_lang_math_abs" ); break; case java_lang_math_log : tty->print("java_lang_math_log" ); break; case java_lang_math_log10 : tty->print("java_lang_math_log10" ); break; diff --git a/src/hotspot/share/interpreter/abstractInterpreter.hpp b/src/hotspot/share/interpreter/abstractInterpreter.hpp index e487b152b76ea..790706c2de3cd 100644 --- a/src/hotspot/share/interpreter/abstractInterpreter.hpp +++ b/src/hotspot/share/interpreter/abstractInterpreter.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -72,6 +72,7 @@ class AbstractInterpreter: AllStatic { java_lang_math_sin, // implementation of java.lang.Math.sin (x) java_lang_math_cos, // implementation of java.lang.Math.cos (x) java_lang_math_tan, // implementation of java.lang.Math.tan (x) + java_lang_math_tanh, // implementation of java.lang.Math.tanh (x) java_lang_math_abs, // implementation of java.lang.Math.abs (x) java_lang_math_sqrt, // implementation of java.lang.Math.sqrt (x) java_lang_math_sqrt_strict, // implementation of java.lang.StrictMath.sqrt(x) @@ -151,6 +152,7 @@ class AbstractInterpreter: AllStatic { case vmIntrinsics::_dsin : // fall thru case vmIntrinsics::_dcos : // fall thru case vmIntrinsics::_dtan : // fall thru + case vmIntrinsics::_dtanh : // fall thru case vmIntrinsics::_dabs : // fall thru case vmIntrinsics::_dsqrt : // fall thru case vmIntrinsics::_dsqrt_strict : // fall thru diff --git a/src/hotspot/share/interpreter/linkResolver.cpp b/src/hotspot/share/interpreter/linkResolver.cpp index cadc3e8a2e802..36847580d9c63 100644 --- a/src/hotspot/share/interpreter/linkResolver.cpp +++ b/src/hotspot/share/interpreter/linkResolver.cpp @@ -87,7 +87,7 @@ void CallInfo::set_interface(Klass* resolved_klass, // we should pick the vtable index from the resolved method. // In that case, the caller must call set_virtual instead of set_interface. assert(resolved_method->method_holder()->is_interface(), ""); - assert(itable_index == resolved_method()->itable_index(), ""); + assert(itable_index == resolved_method->itable_index(), ""); set_common(resolved_klass, resolved_method, selected_method, CallInfo::itable_call, itable_index, CHECK); } @@ -1541,7 +1541,7 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, } // resolve the method in the receiver class, unless it is private - if (!is_abstract_interpretation && !resolved_method()->is_private()) { + if (!is_abstract_interpretation && !resolved_method->is_private()) { // do lookup based on receiver klass // This search must match the linktime preparation search for itable initialization // to correctly enforce loader constraints for interface method inheritance. @@ -1590,17 +1590,17 @@ void LinkResolver::runtime_resolve_interface_method(CallInfo& result, assert(is_abstract_interpretation || vtable_index == selected_method->vtable_index(), "sanity check"); result.set_virtual(resolved_klass, resolved_method, selected_method, vtable_index, CHECK); } else if (resolved_method->has_itable_index()) { - int itable_index = resolved_method()->itable_index(); + int itable_index = resolved_method->itable_index(); log_develop_trace(itables)(" -- itable index: %d", itable_index); result.set_interface(resolved_klass, resolved_method, selected_method, itable_index, CHECK); } else { int index = resolved_method->vtable_index(); log_develop_trace(itables)(" -- non itable/vtable index: %d", index); assert(index == Method::nonvirtual_vtable_index, "Oops hit another case!"); - assert(resolved_method()->is_private() || - (resolved_method()->is_final() && resolved_method->method_holder() == vmClasses::Object_klass()), + assert(resolved_method->is_private() || + (resolved_method->is_final() && resolved_method->method_holder() == vmClasses::Object_klass()), "Should only have non-virtual invokeinterface for private or final-Object methods!"); - assert(resolved_method()->can_be_statically_bound(), "Should only have non-virtual invokeinterface for statically bound methods!"); + assert(resolved_method->can_be_statically_bound(), "Should only have non-virtual invokeinterface for statically bound methods!"); // This sets up the nonvirtual form of "virtual" call (as needed for final and private methods) result.set_virtual(resolved_klass, resolved_method, resolved_method, index, CHECK); } diff --git a/src/hotspot/share/interpreter/linkResolver.hpp b/src/hotspot/share/interpreter/linkResolver.hpp index 340c7d412d599..69bdf56137d41 100644 --- a/src/hotspot/share/interpreter/linkResolver.hpp +++ b/src/hotspot/share/interpreter/linkResolver.hpp @@ -99,7 +99,6 @@ class CallInfo : public StackObj { // Materialize a java.lang.invoke.ResolvedMethodName for this resolved_method void set_resolved_method_name(TRAPS); - BasicType result_type() const { return selected_method()->result_type(); } CallKind call_kind() const { return _call_kind; } int vtable_index() const { // Even for interface calls the vtable index could be non-negative. diff --git a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp index 9cd6f5ceffbe9..3f497c3360b7e 100644 --- a/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/templateInterpreterGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -192,6 +192,7 @@ void TemplateInterpreterGenerator::generate_all() { method_entry(java_lang_math_sin ) method_entry(java_lang_math_cos ) method_entry(java_lang_math_tan ) + method_entry(java_lang_math_tanh ) method_entry(java_lang_math_abs ) method_entry(java_lang_math_sqrt ) method_entry(java_lang_math_sqrt_strict) @@ -457,6 +458,7 @@ address TemplateInterpreterGenerator::generate_intrinsic_entry(AbstractInterpret case Interpreter::java_lang_math_sin : // fall thru case Interpreter::java_lang_math_cos : // fall thru case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_tanh : // fall thru case Interpreter::java_lang_math_abs : // fall thru case Interpreter::java_lang_math_log : // fall thru case Interpreter::java_lang_math_log10 : // fall thru diff --git a/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp b/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp index e08d9553c3e07..27ea1b9706719 100644 --- a/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp +++ b/src/hotspot/share/interpreter/zero/zeroInterpreterGenerator.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2024, Oracle and/or its affiliates. All rights reserved. * Copyright 2007, 2008, 2009, 2010, 2011 Red Hat, Inc. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * @@ -54,6 +54,7 @@ void ZeroInterpreterGenerator::generate_all() { method_entry(java_lang_math_sin ); method_entry(java_lang_math_cos ); method_entry(java_lang_math_tan ); + method_entry(java_lang_math_tanh ); method_entry(java_lang_math_abs ); method_entry(java_lang_math_sqrt ); method_entry(java_lang_math_sqrt_strict); @@ -95,6 +96,7 @@ address ZeroInterpreterGenerator::generate_method_entry( case Interpreter::java_lang_math_sin : // fall thru case Interpreter::java_lang_math_cos : // fall thru case Interpreter::java_lang_math_tan : // fall thru + case Interpreter::java_lang_math_tanh : // fall thru case Interpreter::java_lang_math_abs : // fall thru case Interpreter::java_lang_math_log : // fall thru case Interpreter::java_lang_math_log10 : // fall thru diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp index fa4b1c75c0573..0773de6ddbaa0 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVM.hpp @@ -116,6 +116,7 @@ class CompilerToVM { static address dsin; static address dcos; static address dtan; + static address dtanh; static address dexp; static address dlog; static address dlog10; diff --git a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp index 26c88abec0f18..1612038008a32 100644 --- a/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp +++ b/src/hotspot/share/jvmci/jvmciCompilerToVMInit.cpp @@ -135,6 +135,7 @@ int CompilerToVM::Data::sizeof_ZStoreBarrierEntry = sizeof(ZStoreBarrierEntry); address CompilerToVM::Data::dsin; address CompilerToVM::Data::dcos; address CompilerToVM::Data::dtan; +address CompilerToVM::Data::dtanh; address CompilerToVM::Data::dexp; address CompilerToVM::Data::dlog; address CompilerToVM::Data::dlog10; @@ -268,6 +269,19 @@ void CompilerToVM::Data::initialize(JVMCI_TRAPS) { SET_TRIGFUNC(dpow); #undef SET_TRIGFUNC + +#define SET_TRIGFUNC_OR_NULL(name) \ + if (StubRoutines::name() != nullptr) { \ + name = StubRoutines::name(); \ + } else { \ + name = nullptr; \ + } + + SET_TRIGFUNC_OR_NULL(dtanh); + +#undef SET_TRIGFUNC_OR_NULL + + } static jboolean is_c1_supported(vmIntrinsics::ID id){ diff --git a/src/hotspot/share/jvmci/jvmci_globals.cpp b/src/hotspot/share/jvmci/jvmci_globals.cpp index 86d8491b73303..36740560dd23f 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.cpp +++ b/src/hotspot/share/jvmci/jvmci_globals.cpp @@ -80,6 +80,15 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() { CHECK_NOT_SET(LibJVMCICompilerThreadHidden, UseJVMCICompiler) if (UseJVMCICompiler) { + if (!FLAG_IS_DEFAULT(EnableJVMCI) && !EnableJVMCI) { + jio_fprintf(defaultStream::error_stream(), + "Improperly specified VM option UseJVMCICompiler: EnableJVMCI cannot be disabled\n"); + return false; + } + FLAG_SET_DEFAULT(EnableJVMCI, true); + } + + if (EnableJVMCI) { if (FLAG_IS_DEFAULT(UseJVMCINativeLibrary) && !UseJVMCINativeLibrary) { char path[JVM_MAXPATHLEN]; if (os::dll_locate_lib(path, sizeof(path), Arguments::get_dll_dir(), JVMCI_SHARED_LIBRARY_NAME)) { @@ -88,12 +97,9 @@ bool JVMCIGlobals::check_jvmci_flags_are_consistent() { FLAG_SET_DEFAULT(UseJVMCINativeLibrary, true); } } - if (!FLAG_IS_DEFAULT(EnableJVMCI) && !EnableJVMCI) { - jio_fprintf(defaultStream::error_stream(), - "Improperly specified VM option UseJVMCICompiler: EnableJVMCI cannot be disabled\n"); - return false; - } - FLAG_SET_DEFAULT(EnableJVMCI, true); + } + + if (UseJVMCICompiler) { if (BootstrapJVMCI && UseJVMCINativeLibrary) { jio_fprintf(defaultStream::error_stream(), "-XX:+BootstrapJVMCI is not compatible with -XX:+UseJVMCINativeLibrary\n"); return false; diff --git a/src/hotspot/share/jvmci/jvmci_globals.hpp b/src/hotspot/share/jvmci/jvmci_globals.hpp index 1f2c0c647ab1e..30f2e6c2c73e0 100644 --- a/src/hotspot/share/jvmci/jvmci_globals.hpp +++ b/src/hotspot/share/jvmci/jvmci_globals.hpp @@ -140,7 +140,7 @@ class fileStream; product(bool, UseJVMCINativeLibrary, false, EXPERIMENTAL, \ "Execute JVMCI Java code from a shared library (\"libjvmci\") " \ "instead of loading it from class files and executing it " \ - "on the HotSpot heap. Defaults to true if EnableJVMCIProduct is " \ + "on the HotSpot heap. Defaults to true if EnableJVMCI is " \ "true and a JVMCI native library is available.") \ \ product(double, JVMCINativeLibraryThreadFraction, 0.33, EXPERIMENTAL, \ diff --git a/src/hotspot/share/logging/logSelection.cpp b/src/hotspot/share/logging/logSelection.cpp index aea5719b36d4f..1e7ba3a887848 100644 --- a/src/hotspot/share/logging/logSelection.cpp +++ b/src/hotspot/share/logging/logSelection.cpp @@ -33,11 +33,11 @@ const LogSelection LogSelection::Invalid; -LogSelection::LogSelection() : _ntags(0), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) { +LogSelection::LogSelection() : _ntags(0), _tags(), _wildcard(false), _level(LogLevel::Invalid), _tag_sets_selected(0) { } LogSelection::LogSelection(const LogTagType tags[LogTag::MaxTags], bool wildcard, LogLevelType level) - : _ntags(0), _wildcard(wildcard), _level(level), _tag_sets_selected(0) { + : _ntags(0), _tags(), _wildcard(wildcard), _level(level), _tag_sets_selected(0) { while (_ntags < LogTag::MaxTags && tags[_ntags] != LogTag::__NO_TAG) { _tags[_ntags] = tags[_ntags]; _ntags++; diff --git a/src/hotspot/share/nmt/mallocHeader.hpp b/src/hotspot/share/nmt/mallocHeader.hpp index c76e61fb4b5a2..6711c2b993e6f 100644 --- a/src/hotspot/share/nmt/mallocHeader.hpp +++ b/src/hotspot/share/nmt/mallocHeader.hpp @@ -127,6 +127,7 @@ class MallocHeader { inline MallocHeader(size_t size, MemTag mem_tag, uint32_t mst_marker); + inline static size_t malloc_overhead() { return sizeof(MallocHeader) + sizeof(uint16_t); } inline size_t size() const { return _size; } inline MemTag mem_tag() const { return _mem_tag; } inline uint32_t mst_marker() const { return _mst_marker; } diff --git a/src/hotspot/share/nmt/mallocTracker.hpp b/src/hotspot/share/nmt/mallocTracker.hpp index 39d120433ef02..de30f32373edf 100644 --- a/src/hotspot/share/nmt/mallocTracker.hpp +++ b/src/hotspot/share/nmt/mallocTracker.hpp @@ -166,7 +166,7 @@ class MallocMemorySnapshot { } inline size_t malloc_overhead() const { - return _all_mallocs.count() * sizeof(MallocHeader); + return _all_mallocs.count() * MallocHeader::malloc_overhead(); } // Total malloc invocation count @@ -269,7 +269,7 @@ class MallocTracker : AllStatic { // The overhead that is incurred by switching on NMT (we need, per malloc allocation, // space for header and 16-bit footer) - static const size_t overhead_per_malloc = sizeof(MallocHeader) + sizeof(uint16_t); + static inline size_t overhead_per_malloc() { return MallocHeader::malloc_overhead(); } // Parameter name convention: // memblock : the beginning address for user data diff --git a/src/hotspot/share/nmt/memTracker.hpp b/src/hotspot/share/nmt/memTracker.hpp index 31b1e66b8a6b3..6ba1db2e7ffe6 100644 --- a/src/hotspot/share/nmt/memTracker.hpp +++ b/src/hotspot/share/nmt/memTracker.hpp @@ -72,7 +72,7 @@ class MemTracker : AllStatic { // Per-malloc overhead incurred by NMT, depending on the current NMT level static size_t overhead_per_malloc() { - return enabled() ? MallocTracker::overhead_per_malloc : 0; + return enabled() ? MallocTracker::overhead_per_malloc() : 0; } static inline void* record_malloc(void* mem_base, size_t size, MemTag mem_tag, diff --git a/src/hotspot/share/oops/compressedOops.cpp b/src/hotspot/share/oops/compressedOops.cpp index 08f78b1d7734c..98a4438383a79 100644 --- a/src/hotspot/share/oops/compressedOops.cpp +++ b/src/hotspot/share/oops/compressedOops.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -35,8 +35,10 @@ #include "runtime/globals.hpp" // For UseCompressedOops. -NarrowPtrStruct CompressedOops::_narrow_oop = { nullptr, 0, true }; -MemRegion CompressedOops::_heap_address_range; +address CompressedOops::_base = nullptr; +int CompressedOops::_shift = 0; +bool CompressedOops::_use_implicit_null_checks = true; +MemRegion CompressedOops::_heap_address_range; // Choose the heap base address and oop encoding mode // when compressed oops are used: @@ -88,16 +90,16 @@ void CompressedOops::initialize(const ReservedHeapSpace& heap_space) { void CompressedOops::set_base(address base) { assert(UseCompressedOops, "no compressed oops?"); - _narrow_oop._base = base; + _base = base; } void CompressedOops::set_shift(int shift) { - _narrow_oop._shift = shift; + _shift = shift; } void CompressedOops::set_use_implicit_null_checks(bool use) { assert(UseCompressedOops, "no compressed ptrs?"); - _narrow_oop._use_implicit_null_checks = use; + _use_implicit_null_checks = use; } bool CompressedOops::is_in(void* addr) { @@ -148,14 +150,14 @@ bool CompressedOops::is_disjoint_heap_base_address(address addr) { // Check for disjoint base compressed oops. bool CompressedOops::base_disjoint() { - return _narrow_oop._base != nullptr && is_disjoint_heap_base_address(_narrow_oop._base); + return _base != nullptr && is_disjoint_heap_base_address(_base); } // Check for real heapbased compressed oops. // We must subtract the base as the bits overlap. // If we negate above function, we also get unscaled and zerobased. bool CompressedOops::base_overlaps() { - return _narrow_oop._base != nullptr && !is_disjoint_heap_base_address(_narrow_oop._base); + return _base != nullptr && !is_disjoint_heap_base_address(_base); } void CompressedOops::print_mode(outputStream* st) { diff --git a/src/hotspot/share/oops/compressedOops.hpp b/src/hotspot/share/oops/compressedOops.hpp index cd3f00393ca44..33af420305cba 100644 --- a/src/hotspot/share/oops/compressedOops.hpp +++ b/src/hotspot/share/oops/compressedOops.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -34,23 +34,18 @@ class outputStream; class ReservedHeapSpace; -struct NarrowPtrStruct { +class CompressedOops : public AllStatic { + friend class VMStructs; + // Base address for oop-within-java-object materialization. // null if using wide oops or zero based narrow oops. - address _base; + static address _base; // Number of shift bits for encoding/decoding narrow ptrs. - // 0 if using wide ptrs or zero based unscaled narrow ptrs, + // 0 if using wide oops or zero based unscaled narrow oops, // LogMinObjAlignmentInBytes otherwise. - int _shift; - // Generate code with implicit null checks for narrow ptrs. - bool _use_implicit_null_checks; -}; - -class CompressedOops : public AllStatic { - friend class VMStructs; - - // For UseCompressedOops. - static NarrowPtrStruct _narrow_oop; + static int _shift; + // Generate code with implicit null checks for narrow oops. + static bool _use_implicit_null_checks; // The address range of the heap static MemRegion _heap_address_range; @@ -73,8 +68,7 @@ class CompressedOops : public AllStatic { UnscaledNarrowOop = 0, ZeroBasedNarrowOop = 1, DisjointBaseNarrowOop = 2, - HeapBasedNarrowOop = 3, - AnyNarrowOopMode = 4 + HeapBasedNarrowOop = 3 }; // The representation type for narrowOop is assumed to be uint32_t. @@ -87,15 +81,13 @@ class CompressedOops : public AllStatic { static void set_shift(int shift); static void set_use_implicit_null_checks(bool use); - static address base() { return _narrow_oop._base; } + static address base() { return _base; } + static address base_addr() { return (address)&_base; } static address begin() { return (address)_heap_address_range.start(); } static address end() { return (address)_heap_address_range.end(); } static bool is_base(void* addr) { return (base() == (address)addr); } - static int shift() { return _narrow_oop._shift; } - static bool use_implicit_null_checks() { return _narrow_oop._use_implicit_null_checks; } - - static address ptrs_base_addr() { return (address)&_narrow_oop._base; } - static address ptrs_base() { return _narrow_oop._base; } + static int shift() { return _shift; } + static bool use_implicit_null_checks() { return _use_implicit_null_checks; } static bool is_in(void* addr); static bool is_in(MemRegion mr); diff --git a/src/hotspot/share/oops/cpCache.cpp b/src/hotspot/share/oops/cpCache.cpp index 817a35959f348..321d8add75594 100644 --- a/src/hotspot/share/oops/cpCache.cpp +++ b/src/hotspot/share/oops/cpCache.cpp @@ -604,6 +604,7 @@ void ConstantPoolCache::adjust_method_entries(bool * trace_name_printed) { if (old_method == nullptr || !old_method->is_old()) { continue; } + assert(!old_method->is_deleted(), "cannot delete these methods"); Method* new_method = old_method->get_new_method(); resolved_indy_entry_at(j)->adjust_method_entry(new_method); log_adjust("indy", old_method, new_method, trace_name_printed); diff --git a/src/hotspot/share/opto/c2_globals.hpp b/src/hotspot/share/opto/c2_globals.hpp index 7288533cd33e7..42de77acca931 100644 --- a/src/hotspot/share/opto/c2_globals.hpp +++ b/src/hotspot/share/opto/c2_globals.hpp @@ -58,6 +58,9 @@ product(bool, StressMacroExpansion, false, DIAGNOSTIC, \ "Randomize macro node expansion order") \ \ + product(bool, StressUnstableIfTraps, false, DIAGNOSTIC, \ + "Randomly take unstable if traps") \ + \ product(uint, StressSeed, 0, DIAGNOSTIC, \ "Seed for randomized stress testing (if unset, a random one is " \ "generated). The seed is recorded in the compilation log, if " \ diff --git a/src/hotspot/share/opto/c2compiler.cpp b/src/hotspot/share/opto/c2compiler.cpp index 2f087858efd48..117e06acd6f31 100644 --- a/src/hotspot/share/opto/c2compiler.cpp +++ b/src/hotspot/share/opto/c2compiler.cpp @@ -610,6 +610,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + case vmIntrinsics::_dtanh: case vmIntrinsics::_dabs: case vmIntrinsics::_fabs: case vmIntrinsics::_iabs: diff --git a/src/hotspot/share/opto/cfgnode.hpp b/src/hotspot/share/opto/cfgnode.hpp index 5edd31fa71695..ac8896705dea0 100644 --- a/src/hotspot/share/opto/cfgnode.hpp +++ b/src/hotspot/share/opto/cfgnode.hpp @@ -347,7 +347,6 @@ class IfNode : public MultiBranchNode { bool is_null_check(ProjNode* proj, PhaseIterGVN* igvn); bool is_side_effect_free_test(ProjNode* proj, PhaseIterGVN* igvn); void reroute_side_effect_free_unc(ProjNode* proj, ProjNode* dom_proj, PhaseIterGVN* igvn); - ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call) const; bool fold_compares_helper(ProjNode* proj, ProjNode* success, ProjNode* fail, PhaseIterGVN* igvn); static bool is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* unc); @@ -442,6 +441,7 @@ class IfNode : public MultiBranchNode { static Node* up_one_dom(Node* curr, bool linear_only = false); bool is_zero_trip_guard() const; Node* dominated_by(Node* prev_dom, PhaseIterGVN* igvn, bool pin_array_access_nodes); + ProjNode* uncommon_trap_proj(CallStaticJavaNode*& call, Deoptimization::DeoptReason reason = Deoptimization::Reason_none) const; // Takes the type of val and filters it through the test represented // by if_proj and returns a more refined type if one is produced. diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index cf282e24c1fc8..e3f3cad4e2d8a 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -725,6 +725,11 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, method()->ensure_method_data(); } + if (StressLCM || StressGCM || StressIGVN || StressCCP || + StressIncrementalInlining || StressMacroExpansion || StressUnstableIfTraps) { + initialize_stress_seed(directive); + } + Init(/*do_aliasing=*/ true); print_compile_messages(); @@ -849,11 +854,6 @@ Compile::Compile( ciEnv* ci_env, ciMethod* target, int osr_bci, if (failing()) return; NOT_PRODUCT( verify_graph_edges(); ) - if (StressLCM || StressGCM || StressIGVN || StressCCP || - StressIncrementalInlining || StressMacroExpansion) { - initialize_stress_seed(directive); - } - // Now optimize Optimize(); if (failing()) return; diff --git a/src/hotspot/share/opto/ifnode.cpp b/src/hotspot/share/opto/ifnode.cpp index 8e5cd2702137a..4313b2cf907a9 100644 --- a/src/hotspot/share/opto/ifnode.cpp +++ b/src/hotspot/share/opto/ifnode.cpp @@ -840,9 +840,9 @@ bool IfNode::is_dominator_unc(CallStaticJavaNode* dom_unc, CallStaticJavaNode* u } // Return projection that leads to an uncommon trap if any -ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call) const { +ProjNode* IfNode::uncommon_trap_proj(CallStaticJavaNode*& call, Deoptimization::DeoptReason reason) const { for (int i = 0; i < 2; i++) { - call = proj_out(i)->is_uncommon_trap_proj(); + call = proj_out(i)->is_uncommon_trap_proj(reason); if (call != nullptr) { return proj_out(i); } diff --git a/src/hotspot/share/opto/library_call.cpp b/src/hotspot/share/opto/library_call.cpp index c95a450272989..8bbb2f8115ec4 100644 --- a/src/hotspot/share/opto/library_call.cpp +++ b/src/hotspot/share/opto/library_call.cpp @@ -254,6 +254,7 @@ bool LibraryCallKit::try_to_inline(int predicate) { case vmIntrinsics::_dsin: case vmIntrinsics::_dcos: case vmIntrinsics::_dtan: + case vmIntrinsics::_dtanh: case vmIntrinsics::_dabs: case vmIntrinsics::_fabs: case vmIntrinsics::_iabs: @@ -1879,6 +1880,9 @@ bool LibraryCallKit::inline_math_native(vmIntrinsics::ID id) { return StubRoutines::dtan() != nullptr ? runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dtan(), "dtan") : runtime_math(OptoRuntime::Math_D_D_Type(), CAST_FROM_FN_PTR(address, SharedRuntime::dtan), "TAN"); + case vmIntrinsics::_dtanh: + return StubRoutines::dtanh() != nullptr ? + runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dtanh(), "dtanh") : false; case vmIntrinsics::_dexp: return StubRoutines::dexp() != nullptr ? runtime_math(OptoRuntime::Math_D_D_Type(), StubRoutines::dexp(), "dexp") : diff --git a/src/hotspot/share/opto/loopnode.cpp b/src/hotspot/share/opto/loopnode.cpp index 3128e23d79c49..b2a1a9d5e2102 100644 --- a/src/hotspot/share/opto/loopnode.cpp +++ b/src/hotspot/share/opto/loopnode.cpp @@ -1918,12 +1918,28 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ // Since stride > 0 and limit_correction <= stride + 1, we can restate this with no over- or underflow into: // max_int - canonicalized_correction - limit_correction >= limit // Since canonicalized_correction and limit_correction are both constants, we can replace them with a new constant: - // final_correction = canonicalized_correction + limit_correction + // (v) final_correction = canonicalized_correction + limit_correction + // // which gives us: // // Final predicate condition: // max_int - final_correction >= limit // + // However, we need to be careful that (v) does not over- or underflow. + // We know that: + // canonicalized_correction = stride - 1 + // and + // limit_correction <= stride + 1 + // and thus + // canonicalized_correction + limit_correction <= 2 * stride + // To prevent an over- or underflow of (v), we must ensure that + // 2 * stride <= max_int + // which can safely be checked without over- or underflow with + // (vi) stride != min_int AND abs(stride) <= max_int / 2 + // + // We could try to further optimize the cases where (vi) does not hold but given that such large strides are + // very uncommon and the loop would only run for a very few iterations anyway, we simply bail out if (vi) fails. + // // (2) Loop Limit Check Predicate for (ii): // Using (ii): init < limit // @@ -1954,6 +1970,10 @@ bool PhaseIdealLoop::is_counted_loop(Node* x, IdealLoopTree*&loop, BasicType iv_ // there is no overflow of the iv phi after the first iteration. In this case, we don't need to check (ii) // again and can skip the predicate. + // Check (vi) and bail out if the stride is too big. + if (stride_con == min_signed_integer(iv_bt) || (ABS(stride_con) > max_signed_integer(iv_bt) / 2)) { + return false; + } // Accounting for (LE3) and (LE4) where we use pre-incremented phis in the loop exit check. const jlong limit_correction_for_pre_iv_exit_check = (phi_incr != nullptr) ? stride_con : 0; diff --git a/src/hotspot/share/opto/parse.hpp b/src/hotspot/share/opto/parse.hpp index a2690aa6704f0..484c49367cc4d 100644 --- a/src/hotspot/share/opto/parse.hpp +++ b/src/hotspot/share/opto/parse.hpp @@ -612,6 +612,11 @@ class Parse : public GraphKit { // Use speculative type to optimize CmpP node Node* optimize_cmp_with_klass(Node* c); + // Stress unstable if traps + void stress_trap(IfNode* orig_iff, Node* counter, Node* incr_store); + // Increment counter used by StressUnstableIfTraps + void increment_trap_stress_counter(Node*& counter, Node*& incr_store); + public: #ifndef PRODUCT // Handle PrintOpto, etc. diff --git a/src/hotspot/share/opto/parse2.cpp b/src/hotspot/share/opto/parse2.cpp index cbd9323c3a93a..6b7cb4eaa99e3 100644 --- a/src/hotspot/share/opto/parse2.cpp +++ b/src/hotspot/share/opto/parse2.cpp @@ -1371,10 +1371,27 @@ inline int Parse::repush_if_args() { return bc_depth; } +// Used by StressUnstableIfTraps +static volatile int _trap_stress_counter = 0; + +void Parse::increment_trap_stress_counter(Node*& counter, Node*& incr_store) { + Node* counter_addr = makecon(TypeRawPtr::make((address)&_trap_stress_counter)); + counter = make_load(control(), counter_addr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, MemNode::unordered); + counter = _gvn.transform(new AddINode(counter, intcon(1))); + incr_store = store_to_memory(control(), counter_addr, counter, T_INT, Compile::AliasIdxRaw, MemNode::unordered); +} + //----------------------------------do_ifnull---------------------------------- void Parse::do_ifnull(BoolTest::mask btest, Node *c) { int target_bci = iter().get_dest(); + Node* counter = nullptr; + Node* incr_store = nullptr; + bool do_stress_trap = StressUnstableIfTraps && ((C->random() % 2) == 0); + if (do_stress_trap) { + increment_trap_stress_counter(counter, incr_store); + } + Block* branch_block = successor_for_bci(target_bci); Block* next_block = successor_for_bci(iter().next_bci()); @@ -1439,6 +1456,10 @@ void Parse::do_ifnull(BoolTest::mask btest, Node *c) { } else { // Path is live. adjust_map_after_if(BoolTest(btest).negate(), c, 1.0-prob, next_block); } + + if (do_stress_trap) { + stress_trap(iff, counter, incr_store); + } } //------------------------------------do_if------------------------------------ @@ -1468,6 +1489,13 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { return; } + Node* counter = nullptr; + Node* incr_store = nullptr; + bool do_stress_trap = StressUnstableIfTraps && ((C->random() % 2) == 0); + if (do_stress_trap) { + increment_trap_stress_counter(counter, incr_store); + } + // Sanity check the probability value assert(0.0f < prob && prob < 1.0f,"Bad probability in Parser"); @@ -1550,9 +1578,58 @@ void Parse::do_if(BoolTest::mask btest, Node* c) { } else { adjust_map_after_if(untaken_btest, c, untaken_prob, next_block); } + + if (do_stress_trap) { + stress_trap(iff, counter, incr_store); + } +} + +// Force unstable if traps to be taken randomly to trigger intermittent bugs such as incorrect debug information. +// Add another if before the unstable if that checks a "random" condition at runtime (a simple shared counter) and +// then either takes the trap or executes the original, unstable if. +void Parse::stress_trap(IfNode* orig_iff, Node* counter, Node* incr_store) { + // Search for an unstable if trap + CallStaticJavaNode* trap = nullptr; + assert(orig_iff->Opcode() == Op_If && orig_iff->outcnt() == 2, "malformed if"); + ProjNode* trap_proj = orig_iff->uncommon_trap_proj(trap, Deoptimization::Reason_unstable_if); + if (trap == nullptr || !trap->jvms()->should_reexecute()) { + // No suitable trap found. Remove unused counter load and increment. + C->gvn_replace_by(incr_store, incr_store->in(MemNode::Memory)); + return; + } + + // Remove trap from optimization list since we add another path to the trap. + bool success = C->remove_unstable_if_trap(trap, true); + assert(success, "Trap already modified"); + + // Add a check before the original if that will trap with a certain frequency and execute the original if otherwise + int freq_log = (C->random() % 31) + 1; // Random logarithmic frequency in [1, 31] + Node* mask = intcon(right_n_bits(freq_log)); + counter = _gvn.transform(new AndINode(counter, mask)); + Node* cmp = _gvn.transform(new CmpINode(counter, intcon(0))); + Node* bol = _gvn.transform(new BoolNode(cmp, BoolTest::mask::eq)); + IfNode* iff = _gvn.transform(new IfNode(orig_iff->in(0), bol, orig_iff->_prob, orig_iff->_fcnt))->as_If(); + Node* if_true = _gvn.transform(new IfTrueNode(iff)); + Node* if_false = _gvn.transform(new IfFalseNode(iff)); + assert(!if_true->is_top() && !if_false->is_top(), "trap always / never taken"); + + // Trap + assert(trap_proj->outcnt() == 1, "some other nodes are dependent on the trap projection"); + + Node* trap_region = new RegionNode(3); + trap_region->set_req(1, trap_proj); + trap_region->set_req(2, if_true); + trap->set_req(0, _gvn.transform(trap_region)); + + // Don't trap, execute original if + orig_iff->set_req(0, if_false); } bool Parse::path_is_suitable_for_uncommon_trap(float prob) const { + // Randomly skip emitting an uncommon trap + if (StressUnstableIfTraps && ((C->random() % 2) == 0)) { + return false; + } // Don't want to speculate on uncommon traps when running with -Xcomp if (!UseInterpreter) { return false; diff --git a/src/hotspot/share/runtime/basicLock.inline.hpp b/src/hotspot/share/runtime/basicLock.inline.hpp index f78537372057d..d977a62a923f4 100644 --- a/src/hotspot/share/runtime/basicLock.inline.hpp +++ b/src/hotspot/share/runtime/basicLock.inline.hpp @@ -45,7 +45,7 @@ inline void BasicLock::set_displaced_header(markWord header) { inline ObjectMonitor* BasicLock::object_monitor_cache() const { assert(UseObjectMonitorTable, "must be"); -#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(LOONGARCH64) +#if defined(X86) || defined(AARCH64) || defined(RISCV64) || defined(PPC64) || defined(S390) || defined(LOONGARCH64) return reinterpret_cast(get_metadata()); #else // Other platforms do not make use of the cache yet, diff --git a/src/hotspot/share/runtime/os.cpp b/src/hotspot/share/runtime/os.cpp index 7722df41916e5..a36252dacbf52 100644 --- a/src/hotspot/share/runtime/os.cpp +++ b/src/hotspot/share/runtime/os.cpp @@ -38,6 +38,7 @@ #include "code/codeCache.hpp" #include "code/vtableStubs.hpp" #include "gc/shared/gcVMOperations.hpp" +#include "gc/shared/oopStorageSet.hpp" #include "interpreter/interpreter.hpp" #include "jvm.h" #include "logging/log.hpp" @@ -1323,6 +1324,11 @@ void os::print_location(outputStream* st, intptr_t x, bool verbose) { } #endif + // Ask if any OopStorage knows about this address. + if (OopStorageSet::print_containing(addr, st)) { + return; + } + // Still nothing? If NMT is enabled, we can ask what it thinks... if (MemTracker::print_containing_region(addr, st)) { return; diff --git a/src/hotspot/share/runtime/stubRoutines.cpp b/src/hotspot/share/runtime/stubRoutines.cpp index c13f64fca4bed..a2b8c1da64490 100644 --- a/src/hotspot/share/runtime/stubRoutines.cpp +++ b/src/hotspot/share/runtime/stubRoutines.cpp @@ -171,6 +171,7 @@ address StubRoutines::_dlibm_sin_cos_huge = nullptr; address StubRoutines::_dlibm_reduce_pi04l = nullptr; address StubRoutines::_dlibm_tan_cot_huge = nullptr; address StubRoutines::_dtan = nullptr; +address StubRoutines::_dtanh = nullptr; address StubRoutines::_f2hf = nullptr; address StubRoutines::_hf2f = nullptr; diff --git a/src/hotspot/share/runtime/stubRoutines.hpp b/src/hotspot/share/runtime/stubRoutines.hpp index f5b932569be81..b58c591bbf75c 100644 --- a/src/hotspot/share/runtime/stubRoutines.hpp +++ b/src/hotspot/share/runtime/stubRoutines.hpp @@ -281,6 +281,7 @@ class StubRoutines: AllStatic { static address _dlibm_reduce_pi04l; static address _dlibm_tan_cot_huge; static address _dtan; + static address _dtanh; static address _fmod; static address _f2hf; @@ -472,6 +473,7 @@ class StubRoutines: AllStatic { static address dlibm_sin_cos_huge() { return _dlibm_sin_cos_huge; } static address dlibm_tan_cot_huge() { return _dlibm_tan_cot_huge; } static address dtan() { return _dtan; } + static address dtanh() { return _dtanh; } // These are versions of the java.lang.Float::floatToFloat16() and float16ToFloat() // methods which perform the same operations as the intrinsic version. diff --git a/src/hotspot/share/runtime/vmStructs.cpp b/src/hotspot/share/runtime/vmStructs.cpp index 41abd97c66983..fd02249e16948 100644 --- a/src/hotspot/share/runtime/vmStructs.cpp +++ b/src/hotspot/share/runtime/vmStructs.cpp @@ -379,9 +379,9 @@ /* CompressedOops */ \ /******************/ \ \ - static_field(CompressedOops, _narrow_oop._base, address) \ - static_field(CompressedOops, _narrow_oop._shift, int) \ - static_field(CompressedOops, _narrow_oop._use_implicit_null_checks, bool) \ + static_field(CompressedOops, _base, address) \ + static_field(CompressedOops, _shift, int) \ + static_field(CompressedOops, _use_implicit_null_checks, bool) \ \ /***************************/ \ /* CompressedKlassPointers */ \ diff --git a/src/java.base/macosx/native/libjli/java_md_macosx.m b/src/java.base/macosx/native/libjli/java_md_macosx.m index 4ac2f2c10a215..c5e7ba580a503 100644 --- a/src/java.base/macosx/native/libjli/java_md_macosx.m +++ b/src/java.base/macosx/native/libjli/java_md_macosx.m @@ -60,115 +60,79 @@ #define LD_LIBRARY_PATH "DYLD_FALLBACK_LIBRARY_PATH" /* - * If a processor / os combination has the ability to run binaries of - * two data models and cohabitation of jre/jdk bits with both data - * models is supported, then DUAL_MODE is defined. MacOSX is a hybrid - * system in that, the universal library can contain all types of libraries - * 32/64 and client/server, thus the spawn is capable of linking with the - * appropriate library as requested. + * Following is the high level flow of the launcher + * code residing in the common java.c and this + * macosx specific java_md_macosx file: * - * Notes: - * 1. VM. DUAL_MODE is disabled, and not supported, however, it is left here in - * for experimentation and perhaps enable it in the future. - * 2. At the time of this writing, the universal library contains only - * a server 64-bit server JVM. - * 3. "-client" command line option is supported merely as a command line flag, - * for, compatibility reasons, however, a server VM will be launched. - */ - -/* - * Flowchart of launcher execs and options processing on unix + * - JLI_Launch function, which is the entry point + * to the launcher, calls CreateExecutionEnvironment. + * + * - CreateExecutionEnvironment does the following + * (not necessarily in this order): + * - determines the relevant JVM type that needs + * to be ultimately created + * - determines the path and asserts the presence + * of libjava and relevant libjvm library + * - removes any JVM selection options from the + * arguments that were passed to the launcher + * + * - CreateExecutionEnvironment then creates a new + * thread, within the same process, to launch the + * application's main() Java method and parks the + * current thread, on which CreateExecutionEnvironment + * was invoked, in Apple's Cocoa event loop. Before + * doing so, CreateExecutionEnvironment maintains a + * state flag to keep note that a new thread has + * been spawned. + * + * - The newly created thread (in which the application's + * main() method will ultimately run) starts right from + * the beginning of the current process' main function, + * which effectively means that JLI_Launch is re-invoked + * on this new thread and the same above sequence of code + * flow repeats again. During this "recursive" call, when + * at the point of creating a new thread in + * CreateExecutionEnvironment, the CreateExecutionEnvironment + * will check for the state flag to see if a new thread + * has already been spawned and upon noticing that it + * has, it will skip spawning any more threads and will + * return back from CreateExecutionEnvironment. + * + * - The control returns back from CreateExecutionEnvironment + * to JLI_Launch, and the thread on which the control + * returns is the thread on which the application's main() + * Java method will be invoked. + * + * - JLI_Launch then invokes LoadJavaVM which dlopen()s the + * JVM library and asserts the presence of JNI Invocation + * Functions "JNI_CreateJavaVM", "JNI_GetDefaultJavaVMInitArgs" + * and "JNI_GetCreatedJavaVMs" in that library. It then sets + * internal function pointers in the launcher to point to + * those functions. + * + * - JLI_Launch then translates any -J options by invoking + * TranslateApplicationArgs. + * + * - JLI_Launch then invokes ParseArguments to parse/process + * the launcher arguments. * - * The selection of the proper vm shared library to open depends on - * several classes of command line options, including vm "flavor" - * options (-client, -server) and the data model options, -d32 and - * -d64, as well as a version specification which may have come from - * the command line or from the manifest of an executable jar file. - * The vm selection options are not passed to the running - * virtual machine; they must be screened out by the launcher. + * - JLI_Launch then ultimately calls JVMInit. * - * The version specification (if any) is processed first by the - * platform independent routine SelectVersion. This may result in - * the exec of the specified launcher version. + * - JVMInit then invokes JavaMain. * - * Now, in most cases,the launcher will dlopen the target libjvm.so. All - * required libraries are loaded by the runtime linker, using the known paths - * baked into the shared libraries at compile time. Therefore, - * in most cases, the launcher will only exec, if the data models are - * mismatched, and will not set any environment variables, regardless of the - * data models. + * - JavaMain, before launching the application, invokes + * PostJVMInit. * + * - PostJVMInit invokes ShowSplashScreen which displays + * a splash screen for the application, if applicable. * + * - Control then returns back from PostJVMInit into + * JavaMain, which then loads the application's main + * class and invokes the relevant main() Java method. * - * Main - * (incoming argv) - * | - * \|/ - * CreateExecutionEnvironment - * (determines desired data model) - * | - * | - * \|/ - * Have Desired Model ? --> NO --> Is Dual-Mode ? --> NO --> Exit(with error) - * | | - * | | - * | \|/ - * | YES - * | | - * | | - * | \|/ - * | CheckJvmType - * | (removes -client, -server etc.) - * | | - * | | - * \|/ \|/ - * YES Find the desired executable/library - * | | - * | | - * \|/ \|/ - * CheckJvmType POINT A - * (removes -client, -server, etc.) - * | - * | - * \|/ - * TranslateDashJArgs... - * (Prepare to pass args to vm) - * | - * | - * \|/ - * ParseArguments - * (processes version options, - * creates argument list for vm, - * etc.) - * | - * | - * \|/ - * POINT A - * | - * | - * \|/ - * Path is desired JRE ? YES --> Continue - * NO - * | - * | - * \|/ - * Paths have well known - * jvm paths ? --> NO --> Continue - * YES - * | - * | - * \|/ - * Does libjvm.so exist - * in any of them ? --> NO --> Continue - * YES - * | - * | - * \|/ - * Re-exec / Spawn - * | - * | - * \|/ - * Main + * - JavaMain then returns back an integer result which + * then gets propagated as a return value all the way + * out of the JLI_Launch function. */ /* Store the name of the executable once computed */ diff --git a/src/java.base/share/classes/java/io/DataInputStream.java b/src/java.base/share/classes/java/io/DataInputStream.java index eab7a6e2f189a..59377aca429ca 100644 --- a/src/java.base/share/classes/java/io/DataInputStream.java +++ b/src/java.base/share/classes/java/io/DataInputStream.java @@ -1,5 +1,6 @@ /* * Copyright (c) 1994, 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 @@ -25,8 +26,11 @@ package java.io; +import jdk.internal.access.JavaLangAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.util.ByteArray; +import java.nio.charset.StandardCharsets; import java.util.Objects; /** @@ -45,6 +49,7 @@ * @since 1.0 */ public class DataInputStream extends FilterInputStream implements DataInput { + private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; private static final char[] EMPTY_CHAR_ARRAY = new char[0]; @@ -573,18 +578,16 @@ public final String readUTF() throws IOException { */ public static final String readUTF(DataInput in) throws IOException { int utflen = in.readUnsignedShort(); - byte[] bytearr; - char[] chararr; + byte[] bytearr = null; if (in instanceof DataInputStream dis) { - if (dis.bytearr.length < utflen) { - dis.bytearr = new byte[utflen*2]; - dis.chararr = new char[utflen*2]; + if (dis.bytearr.length >= utflen) { + bytearr = dis.bytearr; } - chararr = dis.chararr; - bytearr = dis.bytearr; - } else { + } + boolean trusted = false; + if (bytearr == null) { bytearr = new byte[utflen]; - chararr = new char[utflen]; + trusted = true; } int c, char2, char3; @@ -592,12 +595,35 @@ public static final String readUTF(DataInput in) throws IOException { int chararr_count=0; in.readFully(bytearr, 0, utflen); + int ascii = JLA.countPositives(bytearr, 0, utflen); + if (ascii == utflen) { + String str; + if (trusted) { + str = JLA.newStringNoRepl(bytearr, StandardCharsets.ISO_8859_1); + } else { + str = new String(bytearr, 0, utflen, StandardCharsets.ISO_8859_1); + } + return str; + } + if (trusted && in instanceof DataInputStream dis) { + dis.bytearr = bytearr; + trusted = false; + } - while (count < utflen) { - c = (int) bytearr[count] & 0xff; - if (c > 127) break; - count++; - chararr[chararr_count++]=(char)c; + char[] chararr; + if (in instanceof DataInputStream dis) { + if (dis.chararr.length < (utflen << 1)) { + dis.chararr = new char[utflen << 1]; + } + chararr = dis.chararr; + } else { + chararr = new char[utflen]; + } + + if (ascii != 0) { + JLA.inflateBytesToChars(bytearr, 0, chararr, 0, ascii); + count += ascii; + chararr_count += ascii; } while (count < utflen) { diff --git a/src/java.base/share/classes/java/lang/Math.java b/src/java.base/share/classes/java/lang/Math.java index 044982a588af8..6b576c88b4710 100644 --- a/src/java.base/share/classes/java/lang/Math.java +++ b/src/java.base/share/classes/java/lang/Math.java @@ -2737,6 +2737,7 @@ public static double cosh(double x) { * @return The hyperbolic tangent of {@code x}. * @since 1.5 */ + @IntrinsicCandidate public static double tanh(double x) { return StrictMath.tanh(x); } diff --git a/src/java.base/share/classes/java/lang/ThreadBuilders.java b/src/java.base/share/classes/java/lang/ThreadBuilders.java index ca29dc4f53589..234807d4cc2a7 100644 --- a/src/java.base/share/classes/java/lang/ThreadBuilders.java +++ b/src/java.base/share/classes/java/lang/ThreadBuilders.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -34,6 +34,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ThreadFactory; import jdk.internal.misc.Unsafe; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.ContinuationSupport; /** @@ -273,15 +274,9 @@ public ThreadFactory factory() { * Base ThreadFactory implementation. */ private abstract static class BaseThreadFactory implements ThreadFactory { - private static final VarHandle COUNT; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - COUNT = l.findVarHandle(BaseThreadFactory.class, "count", long.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle COUNT = MhUtil.findVarHandle( + MethodHandles.lookup(), "count", long.class); + private final String name; private final int characteristics; private final UncaughtExceptionHandler uhe; diff --git a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java index c4474a248b520..50bfa0b7aa6fb 100644 --- a/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java +++ b/src/java.base/share/classes/java/lang/classfile/AnnotationValue.java @@ -60,7 +60,7 @@ public sealed interface AnnotationValue { /** * Models an annotation value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ANNOTATION}. + * The {@linkplain #tag tag} of this value is {@value TAG_ANNOTATION}. * * @since 22 */ @@ -73,7 +73,7 @@ sealed interface OfAnnotation extends AnnotationValue /** * Models an array value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ARRAY}. + * The {@linkplain #tag tag} of this value is {@value TAG_ARRAY}. * * @since 22 */ @@ -131,7 +131,7 @@ sealed interface OfConstant extends AnnotationValue { /** * Models a string value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_STRING}. + * The {@linkplain #tag tag} of this value is {@value TAG_STRING}. * * @since 22 */ @@ -159,7 +159,7 @@ default String resolvedValue() { /** * Models a double value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_DOUBLE}. + * The {@linkplain #tag tag} of this value is {@value TAG_DOUBLE}. * * @since 22 */ @@ -187,7 +187,7 @@ default Double resolvedValue() { /** * Models a float value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_FLOAT}. + * The {@linkplain #tag tag} of this value is {@value TAG_FLOAT}. * * @since 22 */ @@ -215,7 +215,7 @@ default Float resolvedValue() { /** * Models a long value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_LONG}. + * The {@linkplain #tag tag} of this value is {@value TAG_LONG}. * * @since 22 */ @@ -243,7 +243,7 @@ default Long resolvedValue() { /** * Models an int value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_INT}. + * The {@linkplain #tag tag} of this value is {@value TAG_INT}. * * @since 22 */ @@ -271,7 +271,7 @@ default Integer resolvedValue() { /** * Models a short value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_SHORT}. + * The {@linkplain #tag tag} of this value is {@value TAG_SHORT}. * * @since 22 */ @@ -302,7 +302,7 @@ default Short resolvedValue() { /** * Models a char value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CHAR}. + * The {@linkplain #tag tag} of this value is {@value TAG_CHAR}. * * @since 22 */ @@ -333,7 +333,7 @@ default Character resolvedValue() { /** * Models a byte value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BYTE}. + * The {@linkplain #tag tag} of this value is {@value TAG_BYTE}. * * @since 22 */ @@ -364,7 +364,7 @@ default Byte resolvedValue() { /** * Models a boolean value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_BOOLEAN}. + * The {@linkplain #tag tag} of this value is {@value TAG_BOOLEAN}. * * @since 22 */ @@ -395,7 +395,7 @@ default Boolean resolvedValue() { /** * Models a class value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_CLASS}. + * The {@linkplain #tag tag} of this value is {@value TAG_CLASS}. * * @since 22 */ @@ -413,7 +413,7 @@ default ClassDesc classSymbol() { /** * Models an enum value of an element-value pair. - * The {@linkplain #tag tag} of this value is {@value ClassFile#AEV_ENUM}. + * The {@linkplain #tag tag} of this value is {@value TAG_ENUM}. * * @since 22 */ @@ -432,9 +432,52 @@ default ClassDesc classSymbol() { Utf8Entry constantName(); } + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfByte}. */ + int TAG_BYTE = 'B'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfChar}. */ + int TAG_CHAR = 'C'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfDouble}. */ + int TAG_DOUBLE = 'D'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfFloat}. */ + int TAG_FLOAT = 'F'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfInt}. */ + int TAG_INT = 'I'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfLong}. */ + int TAG_LONG = 'J'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfShort}. */ + int TAG_SHORT = 'S'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfBoolean}. */ + int TAG_BOOLEAN = 'Z'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfString}. */ + int TAG_STRING = 's'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfEnum}. */ + int TAG_ENUM = 'e'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfClass}. */ + int TAG_CLASS = 'c'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfAnnotation}. */ + int TAG_ANNOTATION = '@'; + + /** The {@link #tag() tag} indicating the value of an element-value pair is {@link OfArray}. */ + int TAG_ARRAY = '['; + /** * {@return the tag character for this value as per JVMS {@jvms 4.7.16.1}} * The tag characters have a one-to-one mapping to the types of annotation element values. + * + * @apiNote + * {@code TAG_}-prefixed constants in this class, such as {@link #TAG_INT}, + * describe the possible return values of this method. */ char tag(); diff --git a/src/java.base/share/classes/java/lang/classfile/ClassFile.java b/src/java.base/share/classes/java/lang/classfile/ClassFile.java index a305878d3ebf2..284503ee62714 100644 --- a/src/java.base/share/classes/java/lang/classfile/ClassFile.java +++ b/src/java.base/share/classes/java/lang/classfile/ClassFile.java @@ -512,903 +512,75 @@ default List verify(Path path) throws IOException { /** 0xCAFEBABE */ int MAGIC_NUMBER = 0xCAFEBABE; - /** The integer value used to encode the NOP instruction. */ - int NOP = 0; - - /** The integer value used to encode the ACONST_NULL instruction. */ - int ACONST_NULL = 1; - - /** The integer value used to encode the ICONST_M1 instruction. */ - int ICONST_M1 = 2; - - /** The integer value used to encode the ICONST_0 instruction. */ - int ICONST_0 = 3; - - /** The integer value used to encode the ICONST_1 instruction. */ - int ICONST_1 = 4; - - /** The integer value used to encode the ICONST_2 instruction. */ - int ICONST_2 = 5; - - /** The integer value used to encode the ICONST_3 instruction. */ - int ICONST_3 = 6; - - /** The integer value used to encode the ICONST_4 instruction. */ - int ICONST_4 = 7; - - /** The integer value used to encode the ICONST_5 instruction. */ - int ICONST_5 = 8; - - /** The integer value used to encode the LCONST_0 instruction. */ - int LCONST_0 = 9; - - /** The integer value used to encode the LCONST_1 instruction. */ - int LCONST_1 = 10; - - /** The integer value used to encode the FCONST_0 instruction. */ - int FCONST_0 = 11; - - /** The integer value used to encode the FCONST_1 instruction. */ - int FCONST_1 = 12; - - /** The integer value used to encode the FCONST_2 instruction. */ - int FCONST_2 = 13; - - /** The integer value used to encode the DCONST_0 instruction. */ - int DCONST_0 = 14; - - /** The integer value used to encode the DCONST_1 instruction. */ - int DCONST_1 = 15; - - /** The integer value used to encode the BIPUSH instruction. */ - int BIPUSH = 16; - - /** The integer value used to encode the SIPUSH instruction. */ - int SIPUSH = 17; - - /** The integer value used to encode the LDC instruction. */ - int LDC = 18; - - /** The integer value used to encode the LDC_W instruction. */ - int LDC_W = 19; - - /** The integer value used to encode the LDC2_W instruction. */ - int LDC2_W = 20; - - /** The integer value used to encode the ILOAD instruction. */ - int ILOAD = 21; - - /** The integer value used to encode the LLOAD instruction. */ - int LLOAD = 22; - - /** The integer value used to encode the FLOAD instruction. */ - int FLOAD = 23; - - /** The integer value used to encode the DLOAD instruction. */ - int DLOAD = 24; - - /** The integer value used to encode the ALOAD instruction. */ - int ALOAD = 25; - - /** The integer value used to encode the ILOAD_0 instruction. */ - int ILOAD_0 = 26; - - /** The integer value used to encode the ILOAD_1 instruction. */ - int ILOAD_1 = 27; - - /** The integer value used to encode the ILOAD_2 instruction. */ - int ILOAD_2 = 28; - - /** The integer value used to encode the ILOAD_3 instruction. */ - int ILOAD_3 = 29; - - /** The integer value used to encode the LLOAD_0 instruction. */ - int LLOAD_0 = 30; - - /** The integer value used to encode the LLOAD_1 instruction. */ - int LLOAD_1 = 31; - - /** The integer value used to encode the LLOAD_2 instruction. */ - int LLOAD_2 = 32; - - /** The integer value used to encode the LLOAD_3 instruction. */ - int LLOAD_3 = 33; - - /** The integer value used to encode the FLOAD_0 instruction. */ - int FLOAD_0 = 34; - - /** The integer value used to encode the FLOAD_1 instruction. */ - int FLOAD_1 = 35; - - /** The integer value used to encode the FLOAD_2 instruction. */ - int FLOAD_2 = 36; - - /** The integer value used to encode the FLOAD_3 instruction. */ - int FLOAD_3 = 37; - - /** The integer value used to encode the DLOAD_0 instruction. */ - int DLOAD_0 = 38; - - /** The integer value used to encode the DLOAD_1 instruction. */ - int DLOAD_1 = 39; - - /** The integer value used to encode the DLOAD_2 instruction. */ - int DLOAD_2 = 40; - - /** The integer value used to encode the DLOAD_3 instruction. */ - int DLOAD_3 = 41; - - /** The integer value used to encode the ALOAD_0 instruction. */ - int ALOAD_0 = 42; - - /** The integer value used to encode the ALOAD_1 instruction. */ - int ALOAD_1 = 43; - - /** The integer value used to encode the ALOAD_2 instruction. */ - int ALOAD_2 = 44; - - /** The integer value used to encode the ALOAD_3 instruction. */ - int ALOAD_3 = 45; - - /** The integer value used to encode the IALOAD instruction. */ - int IALOAD = 46; - - /** The integer value used to encode the LALOAD instruction. */ - int LALOAD = 47; - - /** The integer value used to encode the FALOAD instruction. */ - int FALOAD = 48; - - /** The integer value used to encode the DALOAD instruction. */ - int DALOAD = 49; - - /** The integer value used to encode the AALOAD instruction. */ - int AALOAD = 50; - - /** The integer value used to encode the BALOAD instruction. */ - int BALOAD = 51; - - /** The integer value used to encode the CALOAD instruction. */ - int CALOAD = 52; - - /** The integer value used to encode the SALOAD instruction. */ - int SALOAD = 53; - - /** The integer value used to encode the ISTORE instruction. */ - int ISTORE = 54; - - /** The integer value used to encode the LSTORE instruction. */ - int LSTORE = 55; - - /** The integer value used to encode the FSTORE instruction. */ - int FSTORE = 56; - - /** The integer value used to encode the DSTORE instruction. */ - int DSTORE = 57; - - /** The integer value used to encode the ASTORE instruction. */ - int ASTORE = 58; - - /** The integer value used to encode the ISTORE_0 instruction. */ - int ISTORE_0 = 59; - - /** The integer value used to encode the ISTORE_1 instruction. */ - int ISTORE_1 = 60; - - /** The integer value used to encode the ISTORE_2 instruction. */ - int ISTORE_2 = 61; - - /** The integer value used to encode the ISTORE_3 instruction. */ - int ISTORE_3 = 62; - - /** The integer value used to encode the LSTORE_0 instruction. */ - int LSTORE_0 = 63; - - /** The integer value used to encode the LSTORE_1 instruction. */ - int LSTORE_1 = 64; - - /** The integer value used to encode the LSTORE_2 instruction. */ - int LSTORE_2 = 65; - - /** The integer value used to encode the LSTORE_3 instruction. */ - int LSTORE_3 = 66; - - /** The integer value used to encode the FSTORE_0 instruction. */ - int FSTORE_0 = 67; - - /** The integer value used to encode the FSTORE_1 instruction. */ - int FSTORE_1 = 68; - - /** The integer value used to encode the FSTORE_2 instruction. */ - int FSTORE_2 = 69; - - /** The integer value used to encode the FSTORE_3 instruction. */ - int FSTORE_3 = 70; - - /** The integer value used to encode the DSTORE_0 instruction. */ - int DSTORE_0 = 71; - - /** The integer value used to encode the DSTORE_1 instruction. */ - int DSTORE_1 = 72; - - /** The integer value used to encode the DSTORE_2 instruction. */ - int DSTORE_2 = 73; - - /** The integer value used to encode the DSTORE_3 instruction. */ - int DSTORE_3 = 74; - - /** The integer value used to encode the ASTORE_0 instruction. */ - int ASTORE_0 = 75; - - /** The integer value used to encode the ASTORE_1 instruction. */ - int ASTORE_1 = 76; - - /** The integer value used to encode the ASTORE_2 instruction. */ - int ASTORE_2 = 77; - - /** The integer value used to encode the ASTORE_3 instruction. */ - int ASTORE_3 = 78; - - /** The integer value used to encode the IASTORE instruction. */ - int IASTORE = 79; - - /** The integer value used to encode the LASTORE instruction. */ - int LASTORE = 80; - - /** The integer value used to encode the FASTORE instruction. */ - int FASTORE = 81; - - /** The integer value used to encode the DASTORE instruction. */ - int DASTORE = 82; - - /** The integer value used to encode the AASTORE instruction. */ - int AASTORE = 83; - - /** The integer value used to encode the BASTORE instruction. */ - int BASTORE = 84; - - /** The integer value used to encode the CASTORE instruction. */ - int CASTORE = 85; - - /** The integer value used to encode the SASTORE instruction. */ - int SASTORE = 86; - - /** The integer value used to encode the POP instruction. */ - int POP = 87; - - /** The integer value used to encode the POP2 instruction. */ - int POP2 = 88; - - /** The integer value used to encode the DUP instruction. */ - int DUP = 89; - - /** The integer value used to encode the DUP_X1 instruction. */ - int DUP_X1 = 90; - - /** The integer value used to encode the DUP_X2 instruction. */ - int DUP_X2 = 91; - - /** The integer value used to encode the DUP2 instruction. */ - int DUP2 = 92; - - /** The integer value used to encode the DUP2_X1 instruction. */ - int DUP2_X1 = 93; - - /** The integer value used to encode the DUP2_X2 instruction. */ - int DUP2_X2 = 94; - - /** The integer value used to encode the SWAP instruction. */ - int SWAP = 95; - - /** The integer value used to encode the IADD instruction. */ - int IADD = 96; - - /** The integer value used to encode the LADD instruction. */ - int LADD = 97; - - /** The integer value used to encode the FADD instruction. */ - int FADD = 98; - - /** The integer value used to encode the DADD instruction. */ - int DADD = 99; - - /** The integer value used to encode the ISUB instruction. */ - int ISUB = 100; - - /** The integer value used to encode the LSUB instruction. */ - int LSUB = 101; - - /** The integer value used to encode the FSUB instruction. */ - int FSUB = 102; - - /** The integer value used to encode the DSUB instruction. */ - int DSUB = 103; - - /** The integer value used to encode the IMUL instruction. */ - int IMUL = 104; - - /** The integer value used to encode the LMUL instruction. */ - int LMUL = 105; - - /** The integer value used to encode the FMUL instruction. */ - int FMUL = 106; - - /** The integer value used to encode the DMUL instruction. */ - int DMUL = 107; - - /** The integer value used to encode the IDIV instruction. */ - int IDIV = 108; - - /** The integer value used to encode the LDIV instruction. */ - int LDIV = 109; - - /** The integer value used to encode the FDIV instruction. */ - int FDIV = 110; - - /** The integer value used to encode the DDIV instruction. */ - int DDIV = 111; - - /** The integer value used to encode the IREM instruction. */ - int IREM = 112; - - /** The integer value used to encode the LREM instruction. */ - int LREM = 113; - - /** The integer value used to encode the FREM instruction. */ - int FREM = 114; - - /** The integer value used to encode the DREM instruction. */ - int DREM = 115; - - /** The integer value used to encode the INEG instruction. */ - int INEG = 116; - - /** The integer value used to encode the LNEG instruction. */ - int LNEG = 117; - - /** The integer value used to encode the FNEG instruction. */ - int FNEG = 118; - - /** The integer value used to encode the DNEG instruction. */ - int DNEG = 119; - - /** The integer value used to encode the ISHL instruction. */ - int ISHL = 120; - - /** The integer value used to encode the LSHL instruction. */ - int LSHL = 121; - - /** The integer value used to encode the ISHR instruction. */ - int ISHR = 122; - - /** The integer value used to encode the LSHR instruction. */ - int LSHR = 123; - - /** The integer value used to encode the IUSHR instruction. */ - int IUSHR = 124; - - /** The integer value used to encode the LUSHR instruction. */ - int LUSHR = 125; - - /** The integer value used to encode the IAND instruction. */ - int IAND = 126; - - /** The integer value used to encode the LAND instruction. */ - int LAND = 127; - - /** The integer value used to encode the IOR instruction. */ - int IOR = 128; - - /** The integer value used to encode the LOR instruction. */ - int LOR = 129; - - /** The integer value used to encode the IXOR instruction. */ - int IXOR = 130; - - /** The integer value used to encode the LXOR instruction. */ - int LXOR = 131; - - /** The integer value used to encode the IINC instruction. */ - int IINC = 132; - - /** The integer value used to encode the I2L instruction. */ - int I2L = 133; - - /** The integer value used to encode the I2F instruction. */ - int I2F = 134; - - /** The integer value used to encode the I2D instruction. */ - int I2D = 135; - - /** The integer value used to encode the L2I instruction. */ - int L2I = 136; - - /** The integer value used to encode the L2F instruction. */ - int L2F = 137; - - /** The integer value used to encode the L2D instruction. */ - int L2D = 138; - - /** The integer value used to encode the F2I instruction. */ - int F2I = 139; - - /** The integer value used to encode the F2L instruction. */ - int F2L = 140; - - /** The integer value used to encode the F2D instruction. */ - int F2D = 141; - - /** The integer value used to encode the D2I instruction. */ - int D2I = 142; - - /** The integer value used to encode the D2L instruction. */ - int D2L = 143; - - /** The integer value used to encode the D2F instruction. */ - int D2F = 144; - - /** The integer value used to encode the I2B instruction. */ - int I2B = 145; - - /** The integer value used to encode the I2C instruction. */ - int I2C = 146; - - /** The integer value used to encode the I2S instruction. */ - int I2S = 147; - - /** The integer value used to encode the LCMP instruction. */ - int LCMP = 148; - - /** The integer value used to encode the FCMPL instruction. */ - int FCMPL = 149; - - /** The integer value used to encode the FCMPG instruction. */ - int FCMPG = 150; - - /** The integer value used to encode the DCMPL instruction. */ - int DCMPL = 151; - - /** The integer value used to encode the DCMPG instruction. */ - int DCMPG = 152; - - /** The integer value used to encode the IFEQ instruction. */ - int IFEQ = 153; - - /** The integer value used to encode the IFNE instruction. */ - int IFNE = 154; - - /** The integer value used to encode the IFLT instruction. */ - int IFLT = 155; - - /** The integer value used to encode the IFGE instruction. */ - int IFGE = 156; - - /** The integer value used to encode the IFGT instruction. */ - int IFGT = 157; - - /** The integer value used to encode the IFLE instruction. */ - int IFLE = 158; - - /** The integer value used to encode the IF_ICMPEQ instruction. */ - int IF_ICMPEQ = 159; - - /** The integer value used to encode the IF_ICMPNE instruction. */ - int IF_ICMPNE = 160; - - /** The integer value used to encode the IF_ICMPLT instruction. */ - int IF_ICMPLT = 161; - - /** The integer value used to encode the IF_ICMPGE instruction. */ - int IF_ICMPGE = 162; - - /** The integer value used to encode the IF_ICMPGT instruction. */ - int IF_ICMPGT = 163; - - /** The integer value used to encode the IF_ICMPLE instruction. */ - int IF_ICMPLE = 164; - - /** The integer value used to encode the IF_ACMPEQ instruction. */ - int IF_ACMPEQ = 165; - - /** The integer value used to encode the IF_ACMPNE instruction. */ - int IF_ACMPNE = 166; - - /** The integer value used to encode the GOTO instruction. */ - int GOTO = 167; - - /** The integer value used to encode the JSR instruction. */ - int JSR = 168; - - /** The integer value used to encode the RET instruction. */ - int RET = 169; - - /** The integer value used to encode the TABLESWITCH instruction. */ - int TABLESWITCH = 170; - - /** The integer value used to encode the LOOKUPSWITCH instruction. */ - int LOOKUPSWITCH = 171; - - /** The integer value used to encode the IRETURN instruction. */ - int IRETURN = 172; - - /** The integer value used to encode the LRETURN instruction. */ - int LRETURN = 173; - - /** The integer value used to encode the FRETURN instruction. */ - int FRETURN = 174; - - /** The integer value used to encode the DRETURN instruction. */ - int DRETURN = 175; - - /** The integer value used to encode the ARETURN instruction. */ - int ARETURN = 176; - - /** The integer value used to encode the RETURN instruction. */ - int RETURN = 177; - - /** The integer value used to encode the GETSTATIC instruction. */ - int GETSTATIC = 178; - - /** The integer value used to encode the PUTSTATIC instruction. */ - int PUTSTATIC = 179; - - /** The integer value used to encode the GETFIELD instruction. */ - int GETFIELD = 180; - - /** The integer value used to encode the PUTFIELD instruction. */ - int PUTFIELD = 181; - - /** The integer value used to encode the INVOKEVIRTUAL instruction. */ - int INVOKEVIRTUAL = 182; - - /** The integer value used to encode the INVOKESPECIAL instruction. */ - int INVOKESPECIAL = 183; - - /** The integer value used to encode the INVOKESTATIC instruction. */ - int INVOKESTATIC = 184; - - /** The integer value used to encode the INVOKEINTERFACE instruction. */ - int INVOKEINTERFACE = 185; - - /** The integer value used to encode the INVOKEDYNAMIC instruction. */ - int INVOKEDYNAMIC = 186; - - /** The integer value used to encode the NEW instruction. */ - int NEW = 187; - - /** The integer value used to encode the NEWARRAY instruction. */ - int NEWARRAY = 188; - - /** The integer value used to encode the ANEWARRAY instruction. */ - int ANEWARRAY = 189; - - /** The integer value used to encode the ARRAYLENGTH instruction. */ - int ARRAYLENGTH = 190; - - /** The integer value used to encode the ATHROW instruction. */ - int ATHROW = 191; - - /** The integer value used to encode the CHECKCAST instruction. */ - int CHECKCAST = 192; - - /** The integer value used to encode the INSTANCEOF instruction. */ - int INSTANCEOF = 193; - - /** The integer value used to encode the MONITORENTER instruction. */ - int MONITORENTER = 194; - - /** The integer value used to encode the MONITOREXIT instruction. */ - int MONITOREXIT = 195; - - /** The integer value used to encode the WIDE instruction. */ - int WIDE = 196; - - /** The integer value used to encode the MULTIANEWARRAY instruction. */ - int MULTIANEWARRAY = 197; - - /** The integer value used to encode the IFNULL instruction. */ - int IFNULL = 198; - - /** The integer value used to encode the IFNONNULL instruction. */ - int IFNONNULL = 199; - - /** The integer value used to encode the GOTO_W instruction. */ - int GOTO_W = 200; - - /** The integer value used to encode the JSR_W instruction. */ - int JSR_W = 201; - - /** The value of PUBLIC access and property modifier. */ + /** The bit mask of PUBLIC access and property modifier. */ int ACC_PUBLIC = 0x0001; - /** The value of PROTECTED access and property modifier. */ + /** The bit mask of PROTECTED access and property modifier. */ int ACC_PROTECTED = 0x0004; - /** The value of PRIVATE access and property modifier. */ + /** The bit mask of PRIVATE access and property modifier. */ int ACC_PRIVATE = 0x0002; - /** The value of INTERFACE access and property modifier. */ + /** The bit mask of INTERFACE access and property modifier. */ int ACC_INTERFACE = 0x0200; - /** The value of ENUM access and property modifier. */ + /** The bit mask of ENUM access and property modifier. */ int ACC_ENUM = 0x4000; - /** The value of ANNOTATION access and property modifier. */ + /** The bit mask of ANNOTATION access and property modifier. */ int ACC_ANNOTATION = 0x2000; - /** The value of SUPER access and property modifier. */ + /** The bit mask of SUPER access and property modifier. */ int ACC_SUPER = 0x0020; - /** The value of ABSTRACT access and property modifier. */ + /** The bit mask of ABSTRACT access and property modifier. */ int ACC_ABSTRACT = 0x0400; - /** The value of VOLATILE access and property modifier. */ + /** The bit mask of VOLATILE access and property modifier. */ int ACC_VOLATILE = 0x0040; - /** The value of TRANSIENT access and property modifier. */ + /** The bit mask of TRANSIENT access and property modifier. */ int ACC_TRANSIENT = 0x0080; - /** The value of SYNTHETIC access and property modifier. */ + /** The bit mask of SYNTHETIC access and property modifier. */ int ACC_SYNTHETIC = 0x1000; - /** The value of STATIC access and property modifier. */ + /** The bit mask of STATIC access and property modifier. */ int ACC_STATIC = 0x0008; - /** The value of FINAL access and property modifier. */ + /** The bit mask of FINAL access and property modifier. */ int ACC_FINAL = 0x0010; - /** The value of SYNCHRONIZED access and property modifier. */ + /** The bit mask of SYNCHRONIZED access and property modifier. */ int ACC_SYNCHRONIZED = 0x0020; - /** The value of BRIDGE access and property modifier. */ + /** The bit mask of BRIDGE access and property modifier. */ int ACC_BRIDGE = 0x0040; - /** The value of VARARGS access and property modifier. */ + /** The bit mask of VARARGS access and property modifier. */ int ACC_VARARGS = 0x0080; - /** The value of NATIVE access and property modifier. */ + /** The bit mask of NATIVE access and property modifier. */ int ACC_NATIVE = 0x0100; - /** The value of STRICT access and property modifier. */ + /** The bit mask of STRICT access and property modifier. */ int ACC_STRICT = 0x0800; - /** The value of MODULE access and property modifier. */ + /** The bit mask of MODULE access and property modifier. */ int ACC_MODULE = 0x8000; - /** The value of OPEN access and property modifier. */ + /** The bit mask of OPEN access and property modifier. */ int ACC_OPEN = 0x20; - /** The value of MANDATED access and property modifier. */ + /** The bit mask of MANDATED access and property modifier. */ int ACC_MANDATED = 0x8000; - /** The value of TRANSITIVE access and property modifier. */ + /** The bit mask of TRANSITIVE access and property modifier. */ int ACC_TRANSITIVE = 0x20; - /** The value of STATIC_PHASE access and property modifier. */ + /** The bit mask of STATIC_PHASE access and property modifier. */ int ACC_STATIC_PHASE = 0x40; - /** The value of STATEMENT {@link CharacterRangeInfo} kind. */ - int CRT_STATEMENT = 0x0001; - - /** The value of BLOCK {@link CharacterRangeInfo} kind. */ - int CRT_BLOCK = 0x0002; - - /** The value of ASSIGNMENT {@link CharacterRangeInfo} kind. */ - int CRT_ASSIGNMENT = 0x0004; - - /** The value of FLOW_CONTROLLER {@link CharacterRangeInfo} kind. */ - int CRT_FLOW_CONTROLLER = 0x0008; - - /** The value of FLOW_TARGET {@link CharacterRangeInfo} kind. */ - int CRT_FLOW_TARGET = 0x0010; - - /** The value of INVOKE {@link CharacterRangeInfo} kind. */ - int CRT_INVOKE = 0x0020; - - /** The value of CREATE {@link CharacterRangeInfo} kind. */ - int CRT_CREATE = 0x0040; - - /** The value of BRANCH_TRUE {@link CharacterRangeInfo} kind. */ - int CRT_BRANCH_TRUE = 0x0080; - - /** The value of BRANCH_FALSE {@link CharacterRangeInfo} kind. */ - int CRT_BRANCH_FALSE = 0x0100; - - /** The value of constant pool tag CLASS. */ - int TAG_CLASS = 7; - - /** The value of constant pool tag CONSTANTDYNAMIC. */ - int TAG_CONSTANTDYNAMIC = 17; - - /** The value of constant pool tag DOUBLE. */ - int TAG_DOUBLE = 6; - - /** The value of constant pool tag FIELDREF. */ - int TAG_FIELDREF = 9; - - /** The value of constant pool tag FLOAT. */ - int TAG_FLOAT = 4; - - /** The value of constant pool tag INTEGER. */ - int TAG_INTEGER = 3; - - /** The value of constant pool tag INTERFACEMETHODREF. */ - int TAG_INTERFACEMETHODREF = 11; - - /** The value of constant pool tag INVOKEDYNAMIC. */ - int TAG_INVOKEDYNAMIC = 18; - - /** The value of constant pool tag LONG. */ - int TAG_LONG = 5; - - /** The value of constant pool tag METHODHANDLE. */ - int TAG_METHODHANDLE = 15; - - /** The value of constant pool tag METHODREF. */ - int TAG_METHODREF = 10; - - /** The value of constant pool tag METHODTYPE. */ - int TAG_METHODTYPE = 16; - - /** The value of constant pool tag MODULE. */ - int TAG_MODULE = 19; - - /** The value of constant pool tag NAMEANDTYPE. */ - int TAG_NAMEANDTYPE = 12; - - /** The value of constant pool tag PACKAGE. */ - int TAG_PACKAGE = 20; - - /** The value of constant pool tag STRING. */ - int TAG_STRING = 8; - - /** The value of constant pool tag UNICODE. */ - int TAG_UNICODE = 2; - - /** The value of constant pool tag UTF8. */ - int TAG_UTF8 = 1; - - // annotation element values - - /** The value of annotation element value type AEV_BYTE. */ - int AEV_BYTE = 'B'; - - /** The value of annotation element value type AEV_CHAR. */ - int AEV_CHAR = 'C'; - - /** The value of annotation element value type AEV_DOUBLE. */ - int AEV_DOUBLE = 'D'; - - /** The value of annotation element value type AEV_FLOAT. */ - int AEV_FLOAT = 'F'; - - /** The value of annotation element value type AEV_INT. */ - int AEV_INT = 'I'; - - /** The value of annotation element value type AEV_LONG. */ - int AEV_LONG = 'J'; - - /** The value of annotation element value type AEV_SHORT. */ - int AEV_SHORT = 'S'; - - /** The value of annotation element value type AEV_BOOLEAN. */ - int AEV_BOOLEAN = 'Z'; - - /** The value of annotation element value type AEV_STRING. */ - int AEV_STRING = 's'; - - /** The value of annotation element value type AEV_ENUM. */ - int AEV_ENUM = 'e'; - - /** The value of annotation element value type AEV_CLASS. */ - int AEV_CLASS = 'c'; - - /** The value of annotation element value type AEV_ANNOTATION. */ - int AEV_ANNOTATION = '@'; - - /** The value of annotation element value type AEV_ARRAY. */ - int AEV_ARRAY = '['; - - //type annotations - - /** The value of type annotation target type CLASS_TYPE_PARAMETER. */ - int TAT_CLASS_TYPE_PARAMETER = 0x00; - - /** The value of type annotation target type METHOD_TYPE_PARAMETER. */ - int TAT_METHOD_TYPE_PARAMETER = 0x01; - - /** The value of type annotation target type CLASS_EXTENDS. */ - int TAT_CLASS_EXTENDS = 0x10; - - /** The value of type annotation target type CLASS_TYPE_PARAMETER_BOUND. */ - int TAT_CLASS_TYPE_PARAMETER_BOUND = 0x11; - - /** The value of type annotation target type METHOD_TYPE_PARAMETER_BOUND. */ - int TAT_METHOD_TYPE_PARAMETER_BOUND = 0x12; - - /** The value of type annotation target type FIELD. */ - int TAT_FIELD = 0x13; - - /** The value of type annotation target type METHOD_RETURN. */ - int TAT_METHOD_RETURN = 0x14; - - /** The value of type annotation target type METHOD_RECEIVER. */ - int TAT_METHOD_RECEIVER = 0x15; - - /** The value of type annotation target type METHOD_FORMAL_PARAMETER. */ - int TAT_METHOD_FORMAL_PARAMETER = 0x16; - - /** The value of type annotation target type THROWS. */ - int TAT_THROWS = 0x17; - - /** The value of type annotation target type LOCAL_VARIABLE. */ - int TAT_LOCAL_VARIABLE = 0x40; - - /** The value of type annotation target type RESOURCE_VARIABLE. */ - int TAT_RESOURCE_VARIABLE = 0x41; - - /** The value of type annotation target type EXCEPTION_PARAMETER. */ - int TAT_EXCEPTION_PARAMETER = 0x42; - - /** The value of type annotation target type INSTANCEOF. */ - int TAT_INSTANCEOF = 0x43; - - /** The value of type annotation target type NEW. */ - int TAT_NEW = 0x44; - - /** The value of type annotation target type CONSTRUCTOR_REFERENCE. */ - int TAT_CONSTRUCTOR_REFERENCE = 0x45; - - /** The value of type annotation target type METHOD_REFERENCE. */ - int TAT_METHOD_REFERENCE = 0x46; - - /** The value of type annotation target type CAST. */ - int TAT_CAST = 0x47; - - /** The value of type annotation target type CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT. */ - int TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; - - /** The value of type annotation target type METHOD_INVOCATION_TYPE_ARGUMENT. */ - int TAT_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; - - /** The value of type annotation target type CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT. */ - int TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; - - /** The value of type annotation target type METHOD_REFERENCE_TYPE_ARGUMENT. */ - int TAT_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; - - //stackmap verification types - - /** The value of verification type TOP. */ - int VT_TOP = 0; - - /** The value of verification type INTEGER. */ - int VT_INTEGER = 1; - - /** The value of verification type FLOAT. */ - int VT_FLOAT = 2; - - /** The value of verification type DOUBLE. */ - int VT_DOUBLE = 3; - - /** The value of verification type LONG. */ - int VT_LONG = 4; - - /** The value of verification type NULL. */ - int VT_NULL = 5; - - /** The value of verification type UNINITIALIZED_THIS. */ - int VT_UNINITIALIZED_THIS = 6; - - /** The value of verification type OBJECT. */ - int VT_OBJECT = 7; - - /** The value of verification type UNINITIALIZED. */ - int VT_UNINITIALIZED = 8; - - /** The value of default class access flags */ - int DEFAULT_CLASS_FLAGS = ACC_PUBLIC; - /** The class major version of JAVA_1. */ int JAVA_1_VERSION = 45; diff --git a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java index 5f4e5b72a1919..16f513801a249 100644 --- a/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java +++ b/src/java.base/share/classes/java/lang/classfile/CodeBuilder.java @@ -615,36 +615,77 @@ default CodeBuilder loadConstant(ConstantDesc value) { if (value == null || value == ConstantDescs.NULL) return aconst_null(); if (value instanceof Number) { - if (value instanceof Integer iVal) - return switch (iVal) { - case -1 -> iconst_m1(); - case 0 -> iconst_0(); - case 1 -> iconst_1(); - case 2 -> iconst_2(); - case 3 -> iconst_3(); - case 4 -> iconst_4(); - case 5 -> iconst_5(); - default -> (iVal >= Byte.MIN_VALUE && iVal <= Byte.MAX_VALUE) ? bipush(iVal) - : (iVal >= Short.MIN_VALUE && iVal <= Short.MAX_VALUE) ? sipush(iVal) - : ldc(constantPool().intEntry(iVal)); - }; - if (value instanceof Long lVal) - return lVal == 0L ? lconst_0() - : lVal == 1L ? lconst_1() - : ldc(constantPool().longEntry(lVal)); - if (value instanceof Float fVal) - return Float.floatToRawIntBits(fVal) == 0 ? fconst_0() - : fVal == 1.0f ? fconst_1() - : fVal == 2.0f ? fconst_2() - : ldc(constantPool().floatEntry(fVal)); - if (value instanceof Double dVal) - return Double.doubleToRawLongBits(dVal) == 0L ? dconst_0() - : dVal == 1.0d ? dconst_1() - : ldc(constantPool().doubleEntry(dVal)); + if (value instanceof Integer) return loadConstant((int) value); + if (value instanceof Long ) return loadConstant((long) value); + if (value instanceof Float ) return loadConstant((float) value); + if (value instanceof Double ) return loadConstant((double) value); } return ldc(value); } + + /** + * Generate an instruction pushing a constant int value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Integer.valueOf(value))}. + * @param value the int value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(int value) { + return switch (value) { + case -1 -> iconst_m1(); + case 0 -> iconst_0(); + case 1 -> iconst_1(); + case 2 -> iconst_2(); + case 3 -> iconst_3(); + case 4 -> iconst_4(); + case 5 -> iconst_5(); + default -> (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE ) ? bipush(value) + : (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) ? sipush(value) + : ldc(constantPool().intEntry(value)); + }; + } + + /** + * Generate an instruction pushing a constant long value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Long.valueOf(value))}. + * @param value the long value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(long value) { + return value == 0l ? lconst_0() + : value == 1l ? lconst_1() + : ldc(constantPool().longEntry(value)); + } + + /** + * Generate an instruction pushing a constant float value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Float.valueOf(value))}. + * @param value the float value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(float value) { + return Float.floatToRawIntBits(value) == 0 ? fconst_0() + : value == 1.0f ? fconst_1() + : value == 2.0f ? fconst_2() + : ldc(constantPool().floatEntry(value)); + } + + /** + * Generate an instruction pushing a constant double value onto the operand stack. + * This is identical to {@link #loadConstant(ConstantDesc) loadConstant(Double.valueOf(value))}. + * @param value the double value + * @return this builder + * @since 24 + */ + default CodeBuilder loadConstant(double value) { + return Double.doubleToRawLongBits(value) == 0l ? dconst_0() + : value == 1.0d ? dconst_1() + : ldc(constantPool().doubleEntry(value)); + } + /** * Generate a do nothing instruction * @return this builder diff --git a/src/java.base/share/classes/java/lang/classfile/Opcode.java b/src/java.base/share/classes/java/lang/classfile/Opcode.java index ab991d983453d..735510dbcea3b 100644 --- a/src/java.base/share/classes/java/lang/classfile/Opcode.java +++ b/src/java.base/share/classes/java/lang/classfile/Opcode.java @@ -24,6 +24,7 @@ */ package java.lang.classfile; +import jdk.internal.classfile.impl.RawBytecodeHelper; import jdk.internal.javac.PreviewFeature; /** @@ -40,658 +41,658 @@ public enum Opcode { /** Do nothing */ - NOP(ClassFile.NOP, 1, Kind.NOP), + NOP(RawBytecodeHelper.NOP, 1, Kind.NOP), /** Push null */ - ACONST_NULL(ClassFile.ACONST_NULL, 1, Kind.CONSTANT), + ACONST_NULL(RawBytecodeHelper.ACONST_NULL, 1, Kind.CONSTANT), /** Push int constant -1 */ - ICONST_M1(ClassFile.ICONST_M1, 1, Kind.CONSTANT), + ICONST_M1(RawBytecodeHelper.ICONST_M1, 1, Kind.CONSTANT), /** Push int constant 0 */ - ICONST_0(ClassFile.ICONST_0, 1, Kind.CONSTANT), + ICONST_0(RawBytecodeHelper.ICONST_0, 1, Kind.CONSTANT), /** Push int constant 1 */ - ICONST_1(ClassFile.ICONST_1, 1, Kind.CONSTANT), + ICONST_1(RawBytecodeHelper.ICONST_1, 1, Kind.CONSTANT), /** Push int constant 2 */ - ICONST_2(ClassFile.ICONST_2, 1, Kind.CONSTANT), + ICONST_2(RawBytecodeHelper.ICONST_2, 1, Kind.CONSTANT), /** Push int constant 3 */ - ICONST_3(ClassFile.ICONST_3, 1, Kind.CONSTANT), + ICONST_3(RawBytecodeHelper.ICONST_3, 1, Kind.CONSTANT), /** Push int constant 4 */ - ICONST_4(ClassFile.ICONST_4, 1, Kind.CONSTANT), + ICONST_4(RawBytecodeHelper.ICONST_4, 1, Kind.CONSTANT), /** Push int constant 5 */ - ICONST_5(ClassFile.ICONST_5, 1, Kind.CONSTANT), + ICONST_5(RawBytecodeHelper.ICONST_5, 1, Kind.CONSTANT), /** Push long constant 0 */ - LCONST_0(ClassFile.LCONST_0, 1, Kind.CONSTANT), + LCONST_0(RawBytecodeHelper.LCONST_0, 1, Kind.CONSTANT), /** Push long constant 1 */ - LCONST_1(ClassFile.LCONST_1, 1, Kind.CONSTANT), + LCONST_1(RawBytecodeHelper.LCONST_1, 1, Kind.CONSTANT), /** Push float constant 0 */ - FCONST_0(ClassFile.FCONST_0, 1, Kind.CONSTANT), + FCONST_0(RawBytecodeHelper.FCONST_0, 1, Kind.CONSTANT), /** Push float constant 1 */ - FCONST_1(ClassFile.FCONST_1, 1, Kind.CONSTANT), + FCONST_1(RawBytecodeHelper.FCONST_1, 1, Kind.CONSTANT), /** Push float constant 2 */ - FCONST_2(ClassFile.FCONST_2, 1, Kind.CONSTANT), + FCONST_2(RawBytecodeHelper.FCONST_2, 1, Kind.CONSTANT), /** Push double constant 0 */ - DCONST_0(ClassFile.DCONST_0, 1, Kind.CONSTANT), + DCONST_0(RawBytecodeHelper.DCONST_0, 1, Kind.CONSTANT), /** Push double constant 1 */ - DCONST_1(ClassFile.DCONST_1, 1, Kind.CONSTANT), + DCONST_1(RawBytecodeHelper.DCONST_1, 1, Kind.CONSTANT), /** Push byte */ - BIPUSH(ClassFile.BIPUSH, 2, Kind.CONSTANT), + BIPUSH(RawBytecodeHelper.BIPUSH, 2, Kind.CONSTANT), /** Push short */ - SIPUSH(ClassFile.SIPUSH, 3, Kind.CONSTANT), + SIPUSH(RawBytecodeHelper.SIPUSH, 3, Kind.CONSTANT), /** Push item from run-time constant pool */ - LDC(ClassFile.LDC, 2, Kind.CONSTANT), + LDC(RawBytecodeHelper.LDC, 2, Kind.CONSTANT), /** Push item from run-time constant pool (wide index) */ - LDC_W(ClassFile.LDC_W, 3, Kind.CONSTANT), + LDC_W(RawBytecodeHelper.LDC_W, 3, Kind.CONSTANT), /** Push long or double from run-time constant pool (wide index) */ - LDC2_W(ClassFile.LDC2_W, 3, Kind.CONSTANT), + LDC2_W(RawBytecodeHelper.LDC2_W, 3, Kind.CONSTANT), /** Load int from local variable */ - ILOAD(ClassFile.ILOAD, 2, Kind.LOAD), + ILOAD(RawBytecodeHelper.ILOAD, 2, Kind.LOAD), /** Load long from local variable */ - LLOAD(ClassFile.LLOAD, 2, Kind.LOAD), + LLOAD(RawBytecodeHelper.LLOAD, 2, Kind.LOAD), /** Load float from local variable */ - FLOAD(ClassFile.FLOAD, 2, Kind.LOAD), + FLOAD(RawBytecodeHelper.FLOAD, 2, Kind.LOAD), /** Load double from local variable */ - DLOAD(ClassFile.DLOAD, 2, Kind.LOAD), + DLOAD(RawBytecodeHelper.DLOAD, 2, Kind.LOAD), /** Load reference from local variable */ - ALOAD(ClassFile.ALOAD, 2, Kind.LOAD), + ALOAD(RawBytecodeHelper.ALOAD, 2, Kind.LOAD), /** Load int from local variable 0 */ - ILOAD_0(ClassFile.ILOAD_0, 1, Kind.LOAD), + ILOAD_0(RawBytecodeHelper.ILOAD_0, 1, Kind.LOAD), /** Load int from local variable 1 */ - ILOAD_1(ClassFile.ILOAD_1, 1, Kind.LOAD), + ILOAD_1(RawBytecodeHelper.ILOAD_1, 1, Kind.LOAD), /** Load int from local variable 2 */ - ILOAD_2(ClassFile.ILOAD_2, 1, Kind.LOAD), + ILOAD_2(RawBytecodeHelper.ILOAD_2, 1, Kind.LOAD), /** Load int from local variable3 */ - ILOAD_3(ClassFile.ILOAD_3, 1, Kind.LOAD), + ILOAD_3(RawBytecodeHelper.ILOAD_3, 1, Kind.LOAD), /** Load long from local variable 0 */ - LLOAD_0(ClassFile.LLOAD_0, 1, Kind.LOAD), + LLOAD_0(RawBytecodeHelper.LLOAD_0, 1, Kind.LOAD), /** Load long from local variable 1 */ - LLOAD_1(ClassFile.LLOAD_1, 1, Kind.LOAD), + LLOAD_1(RawBytecodeHelper.LLOAD_1, 1, Kind.LOAD), /** Load long from local variable 2 */ - LLOAD_2(ClassFile.LLOAD_2, 1, Kind.LOAD), + LLOAD_2(RawBytecodeHelper.LLOAD_2, 1, Kind.LOAD), /** Load long from local variable 3 */ - LLOAD_3(ClassFile.LLOAD_3, 1, Kind.LOAD), + LLOAD_3(RawBytecodeHelper.LLOAD_3, 1, Kind.LOAD), /** Load float from local variable 0 */ - FLOAD_0(ClassFile.FLOAD_0, 1, Kind.LOAD), + FLOAD_0(RawBytecodeHelper.FLOAD_0, 1, Kind.LOAD), /** Load float from local variable 1 */ - FLOAD_1(ClassFile.FLOAD_1, 1, Kind.LOAD), + FLOAD_1(RawBytecodeHelper.FLOAD_1, 1, Kind.LOAD), /** Load float from local variable 2 */ - FLOAD_2(ClassFile.FLOAD_2, 1, Kind.LOAD), + FLOAD_2(RawBytecodeHelper.FLOAD_2, 1, Kind.LOAD), /** Load float from local variable 3 */ - FLOAD_3(ClassFile.FLOAD_3, 1, Kind.LOAD), + FLOAD_3(RawBytecodeHelper.FLOAD_3, 1, Kind.LOAD), /** Load double from local variable 0 */ - DLOAD_0(ClassFile.DLOAD_0, 1, Kind.LOAD), + DLOAD_0(RawBytecodeHelper.DLOAD_0, 1, Kind.LOAD), /** Load double from local variable 1 */ - DLOAD_1(ClassFile.DLOAD_1, 1, Kind.LOAD), + DLOAD_1(RawBytecodeHelper.DLOAD_1, 1, Kind.LOAD), /** Load double from local variable 2 */ - DLOAD_2(ClassFile.DLOAD_2, 1, Kind.LOAD), + DLOAD_2(RawBytecodeHelper.DLOAD_2, 1, Kind.LOAD), /** Load double from local variable 3 */ - DLOAD_3(ClassFile.DLOAD_3, 1, Kind.LOAD), + DLOAD_3(RawBytecodeHelper.DLOAD_3, 1, Kind.LOAD), /** Load reference from local variable 0 */ - ALOAD_0(ClassFile.ALOAD_0, 1, Kind.LOAD), + ALOAD_0(RawBytecodeHelper.ALOAD_0, 1, Kind.LOAD), /** Load reference from local variable 1 */ - ALOAD_1(ClassFile.ALOAD_1, 1, Kind.LOAD), + ALOAD_1(RawBytecodeHelper.ALOAD_1, 1, Kind.LOAD), /** Load reference from local variable 2 */ - ALOAD_2(ClassFile.ALOAD_2, 1, Kind.LOAD), + ALOAD_2(RawBytecodeHelper.ALOAD_2, 1, Kind.LOAD), /** Load reference from local variable 3 */ - ALOAD_3(ClassFile.ALOAD_3, 1, Kind.LOAD), + ALOAD_3(RawBytecodeHelper.ALOAD_3, 1, Kind.LOAD), /** Load int from array */ - IALOAD(ClassFile.IALOAD, 1, Kind.ARRAY_LOAD), + IALOAD(RawBytecodeHelper.IALOAD, 1, Kind.ARRAY_LOAD), /** Load long from array */ - LALOAD(ClassFile.LALOAD, 1, Kind.ARRAY_LOAD), + LALOAD(RawBytecodeHelper.LALOAD, 1, Kind.ARRAY_LOAD), /** Load float from array */ - FALOAD(ClassFile.FALOAD, 1, Kind.ARRAY_LOAD), + FALOAD(RawBytecodeHelper.FALOAD, 1, Kind.ARRAY_LOAD), /** Load double from array */ - DALOAD(ClassFile.DALOAD, 1, Kind.ARRAY_LOAD), + DALOAD(RawBytecodeHelper.DALOAD, 1, Kind.ARRAY_LOAD), /** Load reference from array */ - AALOAD(ClassFile.AALOAD, 1, Kind.ARRAY_LOAD), + AALOAD(RawBytecodeHelper.AALOAD, 1, Kind.ARRAY_LOAD), /** Load byte from array */ - BALOAD(ClassFile.BALOAD, 1, Kind.ARRAY_LOAD), + BALOAD(RawBytecodeHelper.BALOAD, 1, Kind.ARRAY_LOAD), /** Load char from array */ - CALOAD(ClassFile.CALOAD, 1, Kind.ARRAY_LOAD), + CALOAD(RawBytecodeHelper.CALOAD, 1, Kind.ARRAY_LOAD), /** Load short from array */ - SALOAD(ClassFile.SALOAD, 1, Kind.ARRAY_LOAD), + SALOAD(RawBytecodeHelper.SALOAD, 1, Kind.ARRAY_LOAD), /** Store int into local variable */ - ISTORE(ClassFile.ISTORE, 2, Kind.STORE), + ISTORE(RawBytecodeHelper.ISTORE, 2, Kind.STORE), /** Store long into local variable */ - LSTORE(ClassFile.LSTORE, 2, Kind.STORE), + LSTORE(RawBytecodeHelper.LSTORE, 2, Kind.STORE), /** Store float into local variable */ - FSTORE(ClassFile.FSTORE, 2, Kind.STORE), + FSTORE(RawBytecodeHelper.FSTORE, 2, Kind.STORE), /** Store double into local variable */ - DSTORE(ClassFile.DSTORE, 2, Kind.STORE), + DSTORE(RawBytecodeHelper.DSTORE, 2, Kind.STORE), /** Store reference into local variable */ - ASTORE(ClassFile.ASTORE, 2, Kind.STORE), + ASTORE(RawBytecodeHelper.ASTORE, 2, Kind.STORE), /** Store int into local variable 0 */ - ISTORE_0(ClassFile.ISTORE_0, 1, Kind.STORE), + ISTORE_0(RawBytecodeHelper.ISTORE_0, 1, Kind.STORE), /** Store int into local variable 1 */ - ISTORE_1(ClassFile.ISTORE_1, 1, Kind.STORE), + ISTORE_1(RawBytecodeHelper.ISTORE_1, 1, Kind.STORE), /** Store int into local variable 2 */ - ISTORE_2(ClassFile.ISTORE_2, 1, Kind.STORE), + ISTORE_2(RawBytecodeHelper.ISTORE_2, 1, Kind.STORE), /** Store int into local variable 3 */ - ISTORE_3(ClassFile.ISTORE_3, 1, Kind.STORE), + ISTORE_3(RawBytecodeHelper.ISTORE_3, 1, Kind.STORE), /** Store long into local variable 0 */ - LSTORE_0(ClassFile.LSTORE_0, 1, Kind.STORE), + LSTORE_0(RawBytecodeHelper.LSTORE_0, 1, Kind.STORE), /** Store long into local variable 1 */ - LSTORE_1(ClassFile.LSTORE_1, 1, Kind.STORE), + LSTORE_1(RawBytecodeHelper.LSTORE_1, 1, Kind.STORE), /** Store long into local variable 2 */ - LSTORE_2(ClassFile.LSTORE_2, 1, Kind.STORE), + LSTORE_2(RawBytecodeHelper.LSTORE_2, 1, Kind.STORE), /** Store long into local variable 3 */ - LSTORE_3(ClassFile.LSTORE_3, 1, Kind.STORE), + LSTORE_3(RawBytecodeHelper.LSTORE_3, 1, Kind.STORE), /** Store float into local variable 0 */ - FSTORE_0(ClassFile.FSTORE_0, 1, Kind.STORE), + FSTORE_0(RawBytecodeHelper.FSTORE_0, 1, Kind.STORE), /** Store float into local variable 1 */ - FSTORE_1(ClassFile.FSTORE_1, 1, Kind.STORE), + FSTORE_1(RawBytecodeHelper.FSTORE_1, 1, Kind.STORE), /** Store float into local variable 2 */ - FSTORE_2(ClassFile.FSTORE_2, 1, Kind.STORE), + FSTORE_2(RawBytecodeHelper.FSTORE_2, 1, Kind.STORE), /** Store float into local variable 3 */ - FSTORE_3(ClassFile.FSTORE_3, 1, Kind.STORE), + FSTORE_3(RawBytecodeHelper.FSTORE_3, 1, Kind.STORE), /** Store double into local variable 0 */ - DSTORE_0(ClassFile.DSTORE_0, 1, Kind.STORE), + DSTORE_0(RawBytecodeHelper.DSTORE_0, 1, Kind.STORE), /** Store double into local variable 1 */ - DSTORE_1(ClassFile.DSTORE_1, 1, Kind.STORE), + DSTORE_1(RawBytecodeHelper.DSTORE_1, 1, Kind.STORE), /** Store double into local variable 2 */ - DSTORE_2(ClassFile.DSTORE_2, 1, Kind.STORE), + DSTORE_2(RawBytecodeHelper.DSTORE_2, 1, Kind.STORE), /** Store double into local variable 3 */ - DSTORE_3(ClassFile.DSTORE_3, 1, Kind.STORE), + DSTORE_3(RawBytecodeHelper.DSTORE_3, 1, Kind.STORE), /** Store reference into local variable 0 */ - ASTORE_0(ClassFile.ASTORE_0, 1, Kind.STORE), + ASTORE_0(RawBytecodeHelper.ASTORE_0, 1, Kind.STORE), /** Store reference into local variable 1 */ - ASTORE_1(ClassFile.ASTORE_1, 1, Kind.STORE), + ASTORE_1(RawBytecodeHelper.ASTORE_1, 1, Kind.STORE), /** Store reference into local variable 2 */ - ASTORE_2(ClassFile.ASTORE_2, 1, Kind.STORE), + ASTORE_2(RawBytecodeHelper.ASTORE_2, 1, Kind.STORE), /** Store reference into local variable 3 */ - ASTORE_3(ClassFile.ASTORE_3, 1, Kind.STORE), + ASTORE_3(RawBytecodeHelper.ASTORE_3, 1, Kind.STORE), /** Store into int array */ - IASTORE(ClassFile.IASTORE, 1, Kind.ARRAY_STORE), + IASTORE(RawBytecodeHelper.IASTORE, 1, Kind.ARRAY_STORE), /** Store into long array */ - LASTORE(ClassFile.LASTORE, 1, Kind.ARRAY_STORE), + LASTORE(RawBytecodeHelper.LASTORE, 1, Kind.ARRAY_STORE), /** Store into float array */ - FASTORE(ClassFile.FASTORE, 1, Kind.ARRAY_STORE), + FASTORE(RawBytecodeHelper.FASTORE, 1, Kind.ARRAY_STORE), /** Store into double array */ - DASTORE(ClassFile.DASTORE, 1, Kind.ARRAY_STORE), + DASTORE(RawBytecodeHelper.DASTORE, 1, Kind.ARRAY_STORE), /** Store into reference array */ - AASTORE(ClassFile.AASTORE, 1, Kind.ARRAY_STORE), + AASTORE(RawBytecodeHelper.AASTORE, 1, Kind.ARRAY_STORE), /** Store into byte array */ - BASTORE(ClassFile.BASTORE, 1, Kind.ARRAY_STORE), + BASTORE(RawBytecodeHelper.BASTORE, 1, Kind.ARRAY_STORE), /** Store into char array */ - CASTORE(ClassFile.CASTORE, 1, Kind.ARRAY_STORE), + CASTORE(RawBytecodeHelper.CASTORE, 1, Kind.ARRAY_STORE), /** Store into short array */ - SASTORE(ClassFile.SASTORE, 1, Kind.ARRAY_STORE), + SASTORE(RawBytecodeHelper.SASTORE, 1, Kind.ARRAY_STORE), /** Pop the top operand stack value */ - POP(ClassFile.POP, 1, Kind.STACK), + POP(RawBytecodeHelper.POP, 1, Kind.STACK), /** Pop the top one or two operand stack values */ - POP2(ClassFile.POP2, 1, Kind.STACK), + POP2(RawBytecodeHelper.POP2, 1, Kind.STACK), /** Duplicate the top operand stack value */ - DUP(ClassFile.DUP, 1, Kind.STACK), + DUP(RawBytecodeHelper.DUP, 1, Kind.STACK), /** Duplicate the top operand stack value and insert two values down */ - DUP_X1(ClassFile.DUP_X1, 1, Kind.STACK), + DUP_X1(RawBytecodeHelper.DUP_X1, 1, Kind.STACK), /** Duplicate the top operand stack value and insert two or three values down */ - DUP_X2(ClassFile.DUP_X2, 1, Kind.STACK), + DUP_X2(RawBytecodeHelper.DUP_X2, 1, Kind.STACK), /** Duplicate the top one or two operand stack values */ - DUP2(ClassFile.DUP2, 1, Kind.STACK), + DUP2(RawBytecodeHelper.DUP2, 1, Kind.STACK), /** Duplicate the top one or two operand stack values and insert two or three values down */ - DUP2_X1(ClassFile.DUP2_X1, 1, Kind.STACK), + DUP2_X1(RawBytecodeHelper.DUP2_X1, 1, Kind.STACK), /** Duplicate the top one or two operand stack values and insert two, three, or four values down */ - DUP2_X2(ClassFile.DUP2_X2, 1, Kind.STACK), + DUP2_X2(RawBytecodeHelper.DUP2_X2, 1, Kind.STACK), /** Swap the top two operand stack values */ - SWAP(ClassFile.SWAP, 1, Kind.STACK), + SWAP(RawBytecodeHelper.SWAP, 1, Kind.STACK), /** Add int */ - IADD(ClassFile.IADD, 1, Kind.OPERATOR), + IADD(RawBytecodeHelper.IADD, 1, Kind.OPERATOR), /** Add long */ - LADD(ClassFile.LADD, 1, Kind.OPERATOR), + LADD(RawBytecodeHelper.LADD, 1, Kind.OPERATOR), /** Add float */ - FADD(ClassFile.FADD, 1, Kind.OPERATOR), + FADD(RawBytecodeHelper.FADD, 1, Kind.OPERATOR), /** Add double */ - DADD(ClassFile.DADD, 1, Kind.OPERATOR), + DADD(RawBytecodeHelper.DADD, 1, Kind.OPERATOR), /** Subtract int */ - ISUB(ClassFile.ISUB, 1, Kind.OPERATOR), + ISUB(RawBytecodeHelper.ISUB, 1, Kind.OPERATOR), /** Subtract long */ - LSUB(ClassFile.LSUB, 1, Kind.OPERATOR), + LSUB(RawBytecodeHelper.LSUB, 1, Kind.OPERATOR), /** Subtract float */ - FSUB(ClassFile.FSUB, 1, Kind.OPERATOR), + FSUB(RawBytecodeHelper.FSUB, 1, Kind.OPERATOR), /** Subtract double */ - DSUB(ClassFile.DSUB, 1, Kind.OPERATOR), + DSUB(RawBytecodeHelper.DSUB, 1, Kind.OPERATOR), /** Multiply int */ - IMUL(ClassFile.IMUL, 1, Kind.OPERATOR), + IMUL(RawBytecodeHelper.IMUL, 1, Kind.OPERATOR), /** Multiply long */ - LMUL(ClassFile.LMUL, 1, Kind.OPERATOR), + LMUL(RawBytecodeHelper.LMUL, 1, Kind.OPERATOR), /** Multiply float */ - FMUL(ClassFile.FMUL, 1, Kind.OPERATOR), + FMUL(RawBytecodeHelper.FMUL, 1, Kind.OPERATOR), /** Multiply double */ - DMUL(ClassFile.DMUL, 1, Kind.OPERATOR), + DMUL(RawBytecodeHelper.DMUL, 1, Kind.OPERATOR), /** Divide int */ - IDIV(ClassFile.IDIV, 1, Kind.OPERATOR), + IDIV(RawBytecodeHelper.IDIV, 1, Kind.OPERATOR), /** Divide long */ - LDIV(ClassFile.LDIV, 1, Kind.OPERATOR), + LDIV(RawBytecodeHelper.LDIV, 1, Kind.OPERATOR), /** Divide float */ - FDIV(ClassFile.FDIV, 1, Kind.OPERATOR), + FDIV(RawBytecodeHelper.FDIV, 1, Kind.OPERATOR), /** Divide double */ - DDIV(ClassFile.DDIV, 1, Kind.OPERATOR), + DDIV(RawBytecodeHelper.DDIV, 1, Kind.OPERATOR), /** Remainder int */ - IREM(ClassFile.IREM, 1, Kind.OPERATOR), + IREM(RawBytecodeHelper.IREM, 1, Kind.OPERATOR), /** Remainder long */ - LREM(ClassFile.LREM, 1, Kind.OPERATOR), + LREM(RawBytecodeHelper.LREM, 1, Kind.OPERATOR), /** Remainder float */ - FREM(ClassFile.FREM, 1, Kind.OPERATOR), + FREM(RawBytecodeHelper.FREM, 1, Kind.OPERATOR), /** Remainder double */ - DREM(ClassFile.DREM, 1, Kind.OPERATOR), + DREM(RawBytecodeHelper.DREM, 1, Kind.OPERATOR), /** Negate int */ - INEG(ClassFile.INEG, 1, Kind.OPERATOR), + INEG(RawBytecodeHelper.INEG, 1, Kind.OPERATOR), /** Negate long */ - LNEG(ClassFile.LNEG, 1, Kind.OPERATOR), + LNEG(RawBytecodeHelper.LNEG, 1, Kind.OPERATOR), /** Negate float */ - FNEG(ClassFile.FNEG, 1, Kind.OPERATOR), + FNEG(RawBytecodeHelper.FNEG, 1, Kind.OPERATOR), /** Negate double */ - DNEG(ClassFile.DNEG, 1, Kind.OPERATOR), + DNEG(RawBytecodeHelper.DNEG, 1, Kind.OPERATOR), /** Shift left int */ - ISHL(ClassFile.ISHL, 1, Kind.OPERATOR), + ISHL(RawBytecodeHelper.ISHL, 1, Kind.OPERATOR), /** Shift left long */ - LSHL(ClassFile.LSHL, 1, Kind.OPERATOR), + LSHL(RawBytecodeHelper.LSHL, 1, Kind.OPERATOR), /** Shift right int */ - ISHR(ClassFile.ISHR, 1, Kind.OPERATOR), + ISHR(RawBytecodeHelper.ISHR, 1, Kind.OPERATOR), /** Shift right long */ - LSHR(ClassFile.LSHR, 1, Kind.OPERATOR), + LSHR(RawBytecodeHelper.LSHR, 1, Kind.OPERATOR), /** Logical shift right int */ - IUSHR(ClassFile.IUSHR, 1, Kind.OPERATOR), + IUSHR(RawBytecodeHelper.IUSHR, 1, Kind.OPERATOR), /** Logical shift right long */ - LUSHR(ClassFile.LUSHR, 1, Kind.OPERATOR), + LUSHR(RawBytecodeHelper.LUSHR, 1, Kind.OPERATOR), /** Boolean AND int */ - IAND(ClassFile.IAND, 1, Kind.OPERATOR), + IAND(RawBytecodeHelper.IAND, 1, Kind.OPERATOR), /** Boolean AND long */ - LAND(ClassFile.LAND, 1, Kind.OPERATOR), + LAND(RawBytecodeHelper.LAND, 1, Kind.OPERATOR), /** Boolean OR int */ - IOR(ClassFile.IOR, 1, Kind.OPERATOR), + IOR(RawBytecodeHelper.IOR, 1, Kind.OPERATOR), /** Boolean OR long */ - LOR(ClassFile.LOR, 1, Kind.OPERATOR), + LOR(RawBytecodeHelper.LOR, 1, Kind.OPERATOR), /** Boolean XOR int */ - IXOR(ClassFile.IXOR, 1, Kind.OPERATOR), + IXOR(RawBytecodeHelper.IXOR, 1, Kind.OPERATOR), /** Boolean XOR long */ - LXOR(ClassFile.LXOR, 1, Kind.OPERATOR), + LXOR(RawBytecodeHelper.LXOR, 1, Kind.OPERATOR), /** Increment local variable by constant */ - IINC(ClassFile.IINC, 3, Kind.INCREMENT), + IINC(RawBytecodeHelper.IINC, 3, Kind.INCREMENT), /** Convert int to long */ - I2L(ClassFile.I2L, 1, Kind.CONVERT), + I2L(RawBytecodeHelper.I2L, 1, Kind.CONVERT), /** Convert int to float */ - I2F(ClassFile.I2F, 1, Kind.CONVERT), + I2F(RawBytecodeHelper.I2F, 1, Kind.CONVERT), /** Convert int to double */ - I2D(ClassFile.I2D, 1, Kind.CONVERT), + I2D(RawBytecodeHelper.I2D, 1, Kind.CONVERT), /** Convert long to int */ - L2I(ClassFile.L2I, 1, Kind.CONVERT), + L2I(RawBytecodeHelper.L2I, 1, Kind.CONVERT), /** Convert long to float */ - L2F(ClassFile.L2F, 1, Kind.CONVERT), + L2F(RawBytecodeHelper.L2F, 1, Kind.CONVERT), /** Convert long to double */ - L2D(ClassFile.L2D, 1, Kind.CONVERT), + L2D(RawBytecodeHelper.L2D, 1, Kind.CONVERT), /** Convert float to int */ - F2I(ClassFile.F2I, 1, Kind.CONVERT), + F2I(RawBytecodeHelper.F2I, 1, Kind.CONVERT), /** Convert float to long */ - F2L(ClassFile.F2L, 1, Kind.CONVERT), + F2L(RawBytecodeHelper.F2L, 1, Kind.CONVERT), /** Convert float to double */ - F2D(ClassFile.F2D, 1, Kind.CONVERT), + F2D(RawBytecodeHelper.F2D, 1, Kind.CONVERT), /** Convert double to int */ - D2I(ClassFile.D2I, 1, Kind.CONVERT), + D2I(RawBytecodeHelper.D2I, 1, Kind.CONVERT), /** Convert double to long */ - D2L(ClassFile.D2L, 1, Kind.CONVERT), + D2L(RawBytecodeHelper.D2L, 1, Kind.CONVERT), /** Convert double to float */ - D2F(ClassFile.D2F, 1, Kind.CONVERT), + D2F(RawBytecodeHelper.D2F, 1, Kind.CONVERT), /** Convert int to byte */ - I2B(ClassFile.I2B, 1, Kind.CONVERT), + I2B(RawBytecodeHelper.I2B, 1, Kind.CONVERT), /** Convert int to char */ - I2C(ClassFile.I2C, 1, Kind.CONVERT), + I2C(RawBytecodeHelper.I2C, 1, Kind.CONVERT), /** Convert int to short */ - I2S(ClassFile.I2S, 1, Kind.CONVERT), + I2S(RawBytecodeHelper.I2S, 1, Kind.CONVERT), /** Compare long */ - LCMP(ClassFile.LCMP, 1, Kind.OPERATOR), + LCMP(RawBytecodeHelper.LCMP, 1, Kind.OPERATOR), /** Compare float */ - FCMPL(ClassFile.FCMPL, 1, Kind.OPERATOR), + FCMPL(RawBytecodeHelper.FCMPL, 1, Kind.OPERATOR), /** Compare float */ - FCMPG(ClassFile.FCMPG, 1, Kind.OPERATOR), + FCMPG(RawBytecodeHelper.FCMPG, 1, Kind.OPERATOR), /** Compare double */ - DCMPL(ClassFile.DCMPL, 1, Kind.OPERATOR), + DCMPL(RawBytecodeHelper.DCMPL, 1, Kind.OPERATOR), /** Compare double */ - DCMPG(ClassFile.DCMPG, 1, Kind.OPERATOR), + DCMPG(RawBytecodeHelper.DCMPG, 1, Kind.OPERATOR), /** Branch if int comparison with zero succeeds */ - IFEQ(ClassFile.IFEQ, 3, Kind.BRANCH), + IFEQ(RawBytecodeHelper.IFEQ, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFNE(ClassFile.IFNE, 3, Kind.BRANCH), + IFNE(RawBytecodeHelper.IFNE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLT(ClassFile.IFLT, 3, Kind.BRANCH), + IFLT(RawBytecodeHelper.IFLT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGE(ClassFile.IFGE, 3, Kind.BRANCH), + IFGE(RawBytecodeHelper.IFGE, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFGT(ClassFile.IFGT, 3, Kind.BRANCH), + IFGT(RawBytecodeHelper.IFGT, 3, Kind.BRANCH), /** Branch if int comparison with zero succeeds */ - IFLE(ClassFile.IFLE, 3, Kind.BRANCH), + IFLE(RawBytecodeHelper.IFLE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPEQ(ClassFile.IF_ICMPEQ, 3, Kind.BRANCH), + IF_ICMPEQ(RawBytecodeHelper.IF_ICMPEQ, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPNE(ClassFile.IF_ICMPNE, 3, Kind.BRANCH), + IF_ICMPNE(RawBytecodeHelper.IF_ICMPNE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLT(ClassFile.IF_ICMPLT, 3, Kind.BRANCH), + IF_ICMPLT(RawBytecodeHelper.IF_ICMPLT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGE(ClassFile.IF_ICMPGE, 3, Kind.BRANCH), + IF_ICMPGE(RawBytecodeHelper.IF_ICMPGE, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPGT(ClassFile.IF_ICMPGT, 3, Kind.BRANCH), + IF_ICMPGT(RawBytecodeHelper.IF_ICMPGT, 3, Kind.BRANCH), /** Branch if int comparison succeeds */ - IF_ICMPLE(ClassFile.IF_ICMPLE, 3, Kind.BRANCH), + IF_ICMPLE(RawBytecodeHelper.IF_ICMPLE, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPEQ(ClassFile.IF_ACMPEQ, 3, Kind.BRANCH), + IF_ACMPEQ(RawBytecodeHelper.IF_ACMPEQ, 3, Kind.BRANCH), /** Branch if reference comparison succeeds */ - IF_ACMPNE(ClassFile.IF_ACMPNE, 3, Kind.BRANCH), + IF_ACMPNE(RawBytecodeHelper.IF_ACMPNE, 3, Kind.BRANCH), /** Branch always */ - GOTO(ClassFile.GOTO, 3, Kind.BRANCH), + GOTO(RawBytecodeHelper.GOTO, 3, Kind.BRANCH), /** * Jump subroutine is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - JSR(ClassFile.JSR, 3, Kind.DISCONTINUED_JSR), + JSR(RawBytecodeHelper.JSR, 3, Kind.DISCONTINUED_JSR), /** * Return from subroutine is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - RET(ClassFile.RET, 2, Kind.DISCONTINUED_RET), + RET(RawBytecodeHelper.RET, 2, Kind.DISCONTINUED_RET), /** Access jump table by index and jump */ - TABLESWITCH(ClassFile.TABLESWITCH, -1, Kind.TABLE_SWITCH), + TABLESWITCH(RawBytecodeHelper.TABLESWITCH, -1, Kind.TABLE_SWITCH), /** Access jump table by key match and jump */ - LOOKUPSWITCH(ClassFile.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), + LOOKUPSWITCH(RawBytecodeHelper.LOOKUPSWITCH, -1, Kind.LOOKUP_SWITCH), /** Return int from method */ - IRETURN(ClassFile.IRETURN, 1, Kind.RETURN), + IRETURN(RawBytecodeHelper.IRETURN, 1, Kind.RETURN), /** Return long from method */ - LRETURN(ClassFile.LRETURN, 1, Kind.RETURN), + LRETURN(RawBytecodeHelper.LRETURN, 1, Kind.RETURN), /** Return float from method */ - FRETURN(ClassFile.FRETURN, 1, Kind.RETURN), + FRETURN(RawBytecodeHelper.FRETURN, 1, Kind.RETURN), /** Return double from method */ - DRETURN(ClassFile.DRETURN, 1, Kind.RETURN), + DRETURN(RawBytecodeHelper.DRETURN, 1, Kind.RETURN), /** Return reference from method */ - ARETURN(ClassFile.ARETURN, 1, Kind.RETURN), + ARETURN(RawBytecodeHelper.ARETURN, 1, Kind.RETURN), /** Return void from method */ - RETURN(ClassFile.RETURN, 1, Kind.RETURN), + RETURN(RawBytecodeHelper.RETURN, 1, Kind.RETURN), /** Get static field from class */ - GETSTATIC(ClassFile.GETSTATIC, 3, Kind.FIELD_ACCESS), + GETSTATIC(RawBytecodeHelper.GETSTATIC, 3, Kind.FIELD_ACCESS), /** Set static field in class */ - PUTSTATIC(ClassFile.PUTSTATIC, 3, Kind.FIELD_ACCESS), + PUTSTATIC(RawBytecodeHelper.PUTSTATIC, 3, Kind.FIELD_ACCESS), /** Fetch field from object */ - GETFIELD(ClassFile.GETFIELD, 3, Kind.FIELD_ACCESS), + GETFIELD(RawBytecodeHelper.GETFIELD, 3, Kind.FIELD_ACCESS), /** Set field in object */ - PUTFIELD(ClassFile.PUTFIELD, 3, Kind.FIELD_ACCESS), + PUTFIELD(RawBytecodeHelper.PUTFIELD, 3, Kind.FIELD_ACCESS), /** Invoke instance method; dispatch based on class */ - INVOKEVIRTUAL(ClassFile.INVOKEVIRTUAL, 3, Kind.INVOKE), + INVOKEVIRTUAL(RawBytecodeHelper.INVOKEVIRTUAL, 3, Kind.INVOKE), /** * Invoke instance method; direct invocation of instance initialization * methods and methods of the current class and its supertypes */ - INVOKESPECIAL(ClassFile.INVOKESPECIAL, 3, Kind.INVOKE), + INVOKESPECIAL(RawBytecodeHelper.INVOKESPECIAL, 3, Kind.INVOKE), /** Invoke a class (static) method */ - INVOKESTATIC(ClassFile.INVOKESTATIC, 3, Kind.INVOKE), + INVOKESTATIC(RawBytecodeHelper.INVOKESTATIC, 3, Kind.INVOKE), /** Invoke interface method */ - INVOKEINTERFACE(ClassFile.INVOKEINTERFACE, 5, Kind.INVOKE), + INVOKEINTERFACE(RawBytecodeHelper.INVOKEINTERFACE, 5, Kind.INVOKE), /** Invoke a dynamically-computed call site */ - INVOKEDYNAMIC(ClassFile.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC), + INVOKEDYNAMIC(RawBytecodeHelper.INVOKEDYNAMIC, 5, Kind.INVOKE_DYNAMIC), /** Create new object */ - NEW(ClassFile.NEW, 3, Kind.NEW_OBJECT), + NEW(RawBytecodeHelper.NEW, 3, Kind.NEW_OBJECT), /** Create new array */ - NEWARRAY(ClassFile.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY), + NEWARRAY(RawBytecodeHelper.NEWARRAY, 2, Kind.NEW_PRIMITIVE_ARRAY), /** Create new array of reference */ - ANEWARRAY(ClassFile.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), + ANEWARRAY(RawBytecodeHelper.ANEWARRAY, 3, Kind.NEW_REF_ARRAY), /** Get length of array */ - ARRAYLENGTH(ClassFile.ARRAYLENGTH, 1, Kind.OPERATOR), + ARRAYLENGTH(RawBytecodeHelper.ARRAYLENGTH, 1, Kind.OPERATOR), /** Throw exception or error */ - ATHROW(ClassFile.ATHROW, 1, Kind.THROW_EXCEPTION), + ATHROW(RawBytecodeHelper.ATHROW, 1, Kind.THROW_EXCEPTION), /** Check whether object is of given type */ - CHECKCAST(ClassFile.CHECKCAST, 3, Kind.TYPE_CHECK), + CHECKCAST(RawBytecodeHelper.CHECKCAST, 3, Kind.TYPE_CHECK), /** Determine if object is of given type */ - INSTANCEOF(ClassFile.INSTANCEOF, 3, Kind.TYPE_CHECK), + INSTANCEOF(RawBytecodeHelper.INSTANCEOF, 3, Kind.TYPE_CHECK), /** Enter monitor for object */ - MONITORENTER(ClassFile.MONITORENTER, 1, Kind.MONITOR), + MONITORENTER(RawBytecodeHelper.MONITORENTER, 1, Kind.MONITOR), /** Exit monitor for object */ - MONITOREXIT(ClassFile.MONITOREXIT, 1, Kind.MONITOR), + MONITOREXIT(RawBytecodeHelper.MONITOREXIT, 1, Kind.MONITOR), /** Create new multidimensional array */ - MULTIANEWARRAY(ClassFile.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), + MULTIANEWARRAY(RawBytecodeHelper.MULTIANEWARRAY, 4, Kind.NEW_MULTI_ARRAY), /** Branch if reference is null */ - IFNULL(ClassFile.IFNULL, 3, Kind.BRANCH), + IFNULL(RawBytecodeHelper.IFNULL, 3, Kind.BRANCH), /** Branch if reference not null */ - IFNONNULL(ClassFile.IFNONNULL, 3, Kind.BRANCH), + IFNONNULL(RawBytecodeHelper.IFNONNULL, 3, Kind.BRANCH), /** Branch always (wide index) */ - GOTO_W(ClassFile.GOTO_W, 5, Kind.BRANCH), + GOTO_W(RawBytecodeHelper.GOTO_W, 5, Kind.BRANCH), /** * Jump subroutine (wide index) is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - JSR_W(ClassFile.JSR_W, 5, Kind.DISCONTINUED_JSR), + JSR_W(RawBytecodeHelper.JSR_W, 5, Kind.DISCONTINUED_JSR), /** Load int from local variable (wide index) */ - ILOAD_W((ClassFile.WIDE << 8) | ClassFile.ILOAD, 4, Kind.LOAD), + ILOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ILOAD, 4, Kind.LOAD), /** Load long from local variable (wide index) */ - LLOAD_W((ClassFile.WIDE << 8) | ClassFile.LLOAD, 4, Kind.LOAD), + LLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.LLOAD, 4, Kind.LOAD), /** Load float from local variable (wide index) */ - FLOAD_W((ClassFile.WIDE << 8) | ClassFile.FLOAD, 4, Kind.LOAD), + FLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.FLOAD, 4, Kind.LOAD), /** Load double from local variable (wide index) */ - DLOAD_W((ClassFile.WIDE << 8) | ClassFile.DLOAD, 4, Kind.LOAD), + DLOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.DLOAD, 4, Kind.LOAD), /** Load reference from local variable (wide index) */ - ALOAD_W((ClassFile.WIDE << 8) | ClassFile.ALOAD, 4, Kind.LOAD), + ALOAD_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ALOAD, 4, Kind.LOAD), /** Store int into local variable (wide index) */ - ISTORE_W((ClassFile.WIDE << 8) | ClassFile.ISTORE, 4, Kind.STORE), + ISTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ISTORE, 4, Kind.STORE), /** Store long into local variable (wide index) */ - LSTORE_W((ClassFile.WIDE << 8) | ClassFile.LSTORE, 4, Kind.STORE), + LSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.LSTORE, 4, Kind.STORE), /** Store float into local variable (wide index) */ - FSTORE_W((ClassFile.WIDE << 8) | ClassFile.FSTORE, 4, Kind.STORE), + FSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.FSTORE, 4, Kind.STORE), /** Store double into local variable (wide index) */ - DSTORE_W((ClassFile.WIDE << 8) | ClassFile.DSTORE, 4, Kind.STORE), + DSTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.DSTORE, 4, Kind.STORE), /** Store reference into local variable (wide index) */ - ASTORE_W((ClassFile.WIDE << 8) | ClassFile.ASTORE, 4, Kind.STORE), + ASTORE_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.ASTORE, 4, Kind.STORE), /** * Return from subroutine (wide index) is discontinued opcode * @see java.lang.classfile.instruction.DiscontinuedInstruction */ - RET_W((ClassFile.WIDE << 8) | ClassFile.RET, 4, Kind.DISCONTINUED_RET), + RET_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.RET, 4, Kind.DISCONTINUED_RET), /** Increment local variable by constant (wide index) */ - IINC_W((ClassFile.WIDE << 8) | ClassFile.IINC, 6, Kind.INCREMENT); + IINC_W((RawBytecodeHelper.WIDE << 8) | RawBytecodeHelper.IINC, 6, Kind.INCREMENT); /** * Kinds of opcodes. @@ -1085,13 +1086,13 @@ public static enum Kind { /** * {@return the opcode value} For {@linkplain #isWide() wide} pseudo-opcodes, returns the - * first 2 bytes of the instruction, which are the {@code wide} opcode and the functional - * local variable opcode, as a U2 value. + * first 2 bytes of the instruction, which are the wide opcode {@code 196} ({@code 0xC4}) + * and the functional opcode, as a U2 value. */ public int bytecode() { return bytecode; } /** - * {@return true if this is a pseudo-opcode modified by {@code wide}} + * {@return true if this is a pseudo-opcode modified by wide opcode} * * @see #ILOAD_W * @see #LLOAD_W diff --git a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java index b6c9aec76a1a3..139c8eef835dc 100644 --- a/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java +++ b/src/java.base/share/classes/java/lang/classfile/TypeAnnotation.java @@ -31,31 +31,10 @@ import java.lang.classfile.attribute.RuntimeVisibleTypeAnnotationsAttribute; import jdk.internal.classfile.impl.TargetInfoImpl; import jdk.internal.classfile.impl.UnboundAttribute; - -import static java.lang.classfile.ClassFile.TAT_CAST; -import static java.lang.classfile.ClassFile.TAT_CLASS_EXTENDS; -import static java.lang.classfile.ClassFile.TAT_CLASS_TYPE_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_CLASS_TYPE_PARAMETER_BOUND; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_REFERENCE; -import static java.lang.classfile.ClassFile.TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_EXCEPTION_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_FIELD; -import static java.lang.classfile.ClassFile.TAT_INSTANCEOF; -import static java.lang.classfile.ClassFile.TAT_LOCAL_VARIABLE; -import static java.lang.classfile.ClassFile.TAT_METHOD_FORMAL_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_METHOD_INVOCATION_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_METHOD_RECEIVER; -import static java.lang.classfile.ClassFile.TAT_METHOD_REFERENCE; -import static java.lang.classfile.ClassFile.TAT_METHOD_REFERENCE_TYPE_ARGUMENT; -import static java.lang.classfile.ClassFile.TAT_METHOD_RETURN; -import static java.lang.classfile.ClassFile.TAT_METHOD_TYPE_PARAMETER; -import static java.lang.classfile.ClassFile.TAT_METHOD_TYPE_PARAMETER_BOUND; -import static java.lang.classfile.ClassFile.TAT_NEW; -import static java.lang.classfile.ClassFile.TAT_RESOURCE_VARIABLE; -import static java.lang.classfile.ClassFile.TAT_THROWS; import jdk.internal.javac.PreviewFeature; +import static java.lang.classfile.TypeAnnotation.TargetInfo.*; + /** * Models a {@code type_annotation} structure (JVMS {@jvms 4.7.20}). This model * indicates the annotated type within a declaration or expression and the part @@ -87,70 +66,70 @@ public sealed interface TypeAnnotation @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public enum TargetType { /** For annotations on a class type parameter declaration. */ - CLASS_TYPE_PARAMETER(TAT_CLASS_TYPE_PARAMETER, 1), + CLASS_TYPE_PARAMETER(TARGET_CLASS_TYPE_PARAMETER, 1), /** For annotations on a method type parameter declaration. */ - METHOD_TYPE_PARAMETER(TAT_METHOD_TYPE_PARAMETER, 1), + METHOD_TYPE_PARAMETER(TARGET_METHOD_TYPE_PARAMETER, 1), /** For annotations on the type of an "extends" or "implements" clause. */ - CLASS_EXTENDS(TAT_CLASS_EXTENDS, 2), + CLASS_EXTENDS(TARGET_CLASS_EXTENDS, 2), /** For annotations on a bound of a type parameter of a class. */ - CLASS_TYPE_PARAMETER_BOUND(TAT_CLASS_TYPE_PARAMETER_BOUND, 2), + CLASS_TYPE_PARAMETER_BOUND(TARGET_CLASS_TYPE_PARAMETER_BOUND, 2), /** For annotations on a bound of a type parameter of a method. */ - METHOD_TYPE_PARAMETER_BOUND(TAT_METHOD_TYPE_PARAMETER_BOUND, 2), + METHOD_TYPE_PARAMETER_BOUND(TARGET_METHOD_TYPE_PARAMETER_BOUND, 2), /** For annotations on a field. */ - FIELD(TAT_FIELD, 0), + FIELD(TARGET_FIELD, 0), /** For annotations on a method return type. */ - METHOD_RETURN(TAT_METHOD_RETURN, 0), + METHOD_RETURN(TARGET_METHOD_RETURN, 0), /** For annotations on the method receiver. */ - METHOD_RECEIVER(TAT_METHOD_RECEIVER, 0), + METHOD_RECEIVER(TARGET_METHOD_RECEIVER, 0), /** For annotations on a method parameter. */ - METHOD_FORMAL_PARAMETER(TAT_METHOD_FORMAL_PARAMETER, 1), + METHOD_FORMAL_PARAMETER(TARGET_METHOD_FORMAL_PARAMETER, 1), /** For annotations on a throws clause in a method declaration. */ - THROWS(TAT_THROWS, 2), + THROWS(TARGET_THROWS, 2), /** For annotations on a local variable. */ - LOCAL_VARIABLE(TAT_LOCAL_VARIABLE, -1), + LOCAL_VARIABLE(TARGET_LOCAL_VARIABLE, -1), /** For annotations on a resource variable. */ - RESOURCE_VARIABLE(TAT_RESOURCE_VARIABLE, -1), + RESOURCE_VARIABLE(TARGET_RESOURCE_VARIABLE, -1), /** For annotations on an exception parameter. */ - EXCEPTION_PARAMETER(TAT_EXCEPTION_PARAMETER, 2), + EXCEPTION_PARAMETER(TARGET_EXCEPTION_PARAMETER, 2), /** For annotations on a type test. */ - INSTANCEOF(TAT_INSTANCEOF, 2), + INSTANCEOF(TARGET_INSTANCEOF, 2), /** For annotations on an object creation expression. */ - NEW(TAT_NEW, 2), + NEW(TARGET_NEW, 2), /** For annotations on a constructor reference receiver. */ - CONSTRUCTOR_REFERENCE(TAT_CONSTRUCTOR_REFERENCE, 2), + CONSTRUCTOR_REFERENCE(TARGET_CONSTRUCTOR_REFERENCE, 2), /** For annotations on a method reference receiver. */ - METHOD_REFERENCE(TAT_METHOD_REFERENCE, 2), + METHOD_REFERENCE(TARGET_METHOD_REFERENCE, 2), /** For annotations on a typecast. */ - CAST(TAT_CAST, 3), + CAST(TARGET_CAST, 3), /** For annotations on a type argument of an object creation expression. */ - CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, 3), + CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT(TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a method call. */ - METHOD_INVOCATION_TYPE_ARGUMENT(TAT_METHOD_INVOCATION_TYPE_ARGUMENT, 3), + METHOD_INVOCATION_TYPE_ARGUMENT(TARGET_METHOD_INVOCATION_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a constructor reference. */ - CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, 3), + CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT(TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT, 3), /** For annotations on a type argument of a method reference. */ - METHOD_REFERENCE_TYPE_ARGUMENT(TAT_METHOD_REFERENCE_TYPE_ARGUMENT, 3); + METHOD_REFERENCE_TYPE_ARGUMENT(TARGET_METHOD_REFERENCE_TYPE_ARGUMENT, 3); private final int targetTypeValue; private final int sizeIfFixed; @@ -162,6 +141,11 @@ private TargetType(int targetTypeValue, int sizeIfFixed) { /** * {@return the target type value} + * + * @apiNote + * {@code TARGET_}-prefixed constants in {@link TargetInfo}, such as {@link + * TargetInfo#TARGET_CLASS_TYPE_PARAMETER}, describe the possible return + * values of this method. */ public int targetTypeValue() { return targetTypeValue; @@ -214,6 +198,146 @@ static TypeAnnotation of(TargetInfo targetInfo, List targetPa @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface TargetInfo { + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_TYPE_PARAMETER CLASS_TYPE_PARAMETER}. + */ + int TARGET_CLASS_TYPE_PARAMETER = 0x00; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_TYPE_PARAMETER METHOD_TYPE_PARAMETER}. + */ + int TARGET_METHOD_TYPE_PARAMETER = 0x01; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_EXTENDS CLASS_EXTENDS}. + */ + int TARGET_CLASS_EXTENDS = 0x10; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CLASS_TYPE_PARAMETER_BOUND + * CLASS_TYPE_PARAMETER_BOUND}. + */ + int TARGET_CLASS_TYPE_PARAMETER_BOUND = 0x11; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_TYPE_PARAMETER_BOUND + * METHOD_TYPE_PARAMETER_BOUND}. + */ + int TARGET_METHOD_TYPE_PARAMETER_BOUND = 0x12; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#FIELD FIELD}. + */ + int TARGET_FIELD = 0x13; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_RETURN METHOD_RETURN}. + */ + int TARGET_METHOD_RETURN = 0x14; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_RECEIVER METHOD_RECEIVER}. + */ + int TARGET_METHOD_RECEIVER = 0x15; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_FORMAL_PARAMETER + * METHOD_FORMAL_PARAMETER}. + */ + int TARGET_METHOD_FORMAL_PARAMETER = 0x16; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#THROWS THROWS}. + */ + int TARGET_THROWS = 0x17; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#LOCAL_VARIABLE LOCAL_VARIABLE}. + */ + int TARGET_LOCAL_VARIABLE = 0x40; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#RESOURCE_VARIABLE RESOURCE_VARIABLE}. + */ + int TARGET_RESOURCE_VARIABLE = 0x41; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#EXCEPTION_PARAMETER EXCEPTION_PARAMETER}. + */ + int TARGET_EXCEPTION_PARAMETER = 0x42; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#INSTANCEOF INSTANCEOF}. + */ + int TARGET_INSTANCEOF = 0x43; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#NEW NEW}. + */ + int TARGET_NEW = 0x44; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_REFERENCE + * CONSTRUCTOR_REFERENCE}. + */ + int TARGET_CONSTRUCTOR_REFERENCE = 0x45; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_REFERENCE METHOD_REFERENCE}. + */ + int TARGET_METHOD_REFERENCE = 0x46; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CAST CAST}. + */ + int TARGET_CAST = 0x47; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT + * CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT}. + */ + int TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT = 0x48; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_INVOCATION_TYPE_ARGUMENT + * METHOD_INVOCATION_TYPE_ARGUMENT}. + */ + int TARGET_METHOD_INVOCATION_TYPE_ARGUMENT = 0x49; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT + * CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT}. + */ + int TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT = 0x4A; + + /** + * The {@linkplain TargetType#targetTypeValue() value} of type annotation {@linkplain + * #targetType target type} {@link TargetType#METHOD_REFERENCE_TYPE_ARGUMENT + * METHOD_REFERENCE_TYPE_ARGUMENT}. + */ + int TARGET_METHOD_REFERENCE_TYPE_ARGUMENT = 0x4B; + /** * {@return the type of the target} */ diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java index 37abcb027132e..126ba1037cefb 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/CharacterRangeInfo.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -24,6 +24,8 @@ */ package java.lang.classfile.attribute; +import java.lang.classfile.instruction.CharacterRange; + import jdk.internal.classfile.impl.UnboundAttribute; import jdk.internal.javac.PreviewFeature; @@ -70,17 +72,17 @@ public sealed interface CharacterRangeInfo * The value of the flags item describes the kind of range. Multiple flags * may be set within flags. *
    - *
  • {@link java.lang.classfile.ClassFile#CRT_STATEMENT} Range is a Statement + *
  • {@link CharacterRange#FLAG_STATEMENT} Range is a Statement * (except ExpressionStatement), StatementExpression {@jls 14.8}, as well as each * VariableDeclaratorId = VariableInitializer of * LocalVariableDeclarationStatement {@jls 14.4} or FieldDeclaration {@jls 8.3} in the * grammar. - *
  • {@link java.lang.classfile.ClassFile#CRT_BLOCK} Range is a Block in the + *
  • {@link CharacterRange#FLAG_BLOCK} Range is a Block in the * grammar. - *
  • {@link java.lang.classfile.ClassFile#CRT_ASSIGNMENT} Range is an assignment + *
  • {@link CharacterRange#FLAG_ASSIGNMENT} Range is an assignment * expression - Expression1 AssignmentOperator Expression1 in the grammar as * well as increment and decrement expressions (both prefix and postfix). - *
  • {@link java.lang.classfile.ClassFile#CRT_FLOW_CONTROLLER} An expression + *
  • {@link CharacterRange#FLAG_FLOW_CONTROLLER} An expression * whose value will effect control flow. {@code Flowcon} in the following: *
          * if ( Flowcon ) Statement [else Statement]
    @@ -92,7 +94,7 @@ public sealed interface CharacterRangeInfo
          * Flowcon && Expression3
          * Flowcon ? Expression : Expression1
          * 
    - *
  • {@link java.lang.classfile.ClassFile#CRT_FLOW_TARGET} Statement or + *
  • {@link CharacterRange#FLAG_FLOW_TARGET} Statement or * expression effected by a CRT_FLOW_CONTROLLER. {@code Flowtarg} in the following: *
          * if ( Flowcon ) Flowtarg [else Flowtarg]
    @@ -103,11 +105,11 @@ public sealed interface CharacterRangeInfo
          * Flowcon && Flowtarg
          * Flowcon ? Flowtarg : Flowtarg
          * 
    - *
  • {@link java.lang.classfile.ClassFile#CRT_INVOKE} Method invocation. For + *
  • {@link CharacterRange#FLAG_INVOKE} Method invocation. For * example: Identifier Arguments. - *
  • {@link java.lang.classfile.ClassFile#CRT_CREATE} New object creation. For + *
  • {@link CharacterRange#FLAG_CREATE} New object creation. For * example: new Creator. - *
  • {@link java.lang.classfile.ClassFile#CRT_BRANCH_TRUE} A condition encoded + *
  • {@link CharacterRange#FLAG_BRANCH_TRUE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is not inverted towards the corresponding branch condition in * the source code. I.e. actual jump occurs if and only if the the source @@ -119,7 +121,7 @@ public sealed interface CharacterRangeInfo * if<cond>, ifnonull, ifnull or goto. CRT_BRANCH_TRUE and * CRT_BRANCH_FALSE are special kinds of entries that can be used to * determine what branch of a condition was chosen during the runtime. - *
  • {@link java.lang.classfile.ClassFile#CRT_BRANCH_FALSE} A condition encoded + *
  • {@link CharacterRange#FLAG_BRANCH_FALSE} A condition encoded * in the branch instruction immediately contained in the code range for * this item is inverted towards the corresponding branch condition in the * source code. I.e. actual jump occurs if and only if the the source code @@ -134,6 +136,7 @@ public sealed interface CharacterRangeInfo * All bits of the flags item not assigned above are reserved for future use. They should be set to zero in generated class files and should be ignored by Java virtual machine implementations. * * @return the flags + * @see CharacterRange#flags() */ int flags(); diff --git a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java index 46caa66ef9adf..3415c89174ae9 100644 --- a/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java +++ b/src/java.base/share/classes/java/lang/classfile/attribute/StackMapFrameInfo.java @@ -32,7 +32,6 @@ import java.lang.classfile.constantpool.ClassEntry; import jdk.internal.classfile.impl.StackMapDecoder; import jdk.internal.classfile.impl.TemporaryConstantPool; -import static java.lang.classfile.ClassFile.*; import jdk.internal.javac.PreviewFeature; /** @@ -85,8 +84,39 @@ public static StackMapFrameInfo of(Label target, @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) sealed interface VerificationTypeInfo { + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#TOP TOP}. */ + int ITEM_TOP = 0; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#INTEGER INTEGER}. */ + int ITEM_INTEGER = 1; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#FLOAT FLOAT}. */ + int ITEM_FLOAT = 2; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#DOUBLE DOUBLE}. */ + int ITEM_DOUBLE = 3; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#LONG LONG}. */ + int ITEM_LONG = 4; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#NULL NULL}. */ + int ITEM_NULL = 5; + + /** The {@link #tag() tag} for verification type info {@link SimpleVerificationTypeInfo#UNINITIALIZED_THIS UNINITIALIZED_THIS}. */ + int ITEM_UNINITIALIZED_THIS = 6; + + /** The {@link #tag() tag} for verification type info {@link ObjectVerificationTypeInfo OBJECT}. */ + int ITEM_OBJECT = 7; + + /** The {@link #tag() tag} for verification type info {@link UninitializedVerificationTypeInfo UNINITIALIZED}. */ + int ITEM_UNINITIALIZED = 8; + /** * {@return the tag of the type info} + * + * @apiNote + * {@code ITEM_}-prefixed constants in this class, such as {@link #ITEM_TOP}, describe the + * possible return values of this method. */ int tag(); } @@ -100,25 +130,25 @@ sealed interface VerificationTypeInfo { public enum SimpleVerificationTypeInfo implements VerificationTypeInfo { /** verification type top */ - ITEM_TOP(VT_TOP), + TOP(ITEM_TOP), /** verification type int */ - ITEM_INTEGER(VT_INTEGER), + INTEGER(ITEM_INTEGER), /** verification type float */ - ITEM_FLOAT(VT_FLOAT), + FLOAT(ITEM_FLOAT), /** verification type double */ - ITEM_DOUBLE(VT_DOUBLE), + DOUBLE(ITEM_DOUBLE), /** verification type long */ - ITEM_LONG(VT_LONG), + LONG(ITEM_LONG), /** verification type null */ - ITEM_NULL(VT_NULL), + NULL(ITEM_NULL), /** verification type uninitializedThis */ - ITEM_UNINITIALIZED_THIS(VT_UNINITIALIZED_THIS); + UNINITIALIZED_THIS(ITEM_UNINITIALIZED_THIS); private final int tag; @@ -134,7 +164,7 @@ public int tag() { } /** - * A stack value for an object type. + * A stack value for an object type. Its {@link #tag() tag} is {@value #ITEM_OBJECT}. * * @since 22 */ @@ -173,7 +203,7 @@ default ClassDesc classSymbol() { } /** - * An uninitialized stack value. + * An uninitialized stack value. Its {@link #tag() tag} is {@value #ITEM_UNINITIALIZED}. * * @since 22 */ diff --git a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java index c8b74a139280e..d2af4c7c11ae5 100644 --- a/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java +++ b/src/java.base/share/classes/java/lang/classfile/constantpool/PoolEntry.java @@ -38,6 +38,57 @@ public sealed interface PoolEntry LoadableConstantEntry, MemberRefEntry, ModuleEntry, NameAndTypeEntry, PackageEntry { + /** The {@linkplain #tag tag} for {@link ClassEntry CONSTANT_Class} constant kind. */ + int TAG_CLASS = 7; + + /** The {@linkplain #tag tag} for {@link DoubleEntry CONSTANT_Double} constant kind. */ + int TAG_DOUBLE = 6; + + /** The {@linkplain #tag tag} for {@link ConstantDynamicEntry CONSTANT_Dynamic} constant kind. */ + int TAG_DYNAMIC = 17; + + /** The {@linkplain #tag tag} for {@link FieldRefEntry CONSTANT_Fieldref} constant kind. */ + int TAG_FIELDREF = 9; + + /** The {@linkplain #tag tag} for {@link FloatEntry CONSTANT_Float} constant kind. */ + int TAG_FLOAT = 4; + + /** The {@linkplain #tag tag} for {@link IntegerEntry CONSTANT_Integer} constant kind. */ + int TAG_INTEGER = 3; + + /** The {@linkplain #tag tag} for {@link InterfaceMethodRefEntry CONSTANT_InterfaceMethodref} constant kind. */ + int TAG_INTERFACE_METHODREF = 11; + + /** The {@linkplain #tag tag} for {@link InvokeDynamicEntry CONSTANT_InvokeDynamic} constant kind. */ + int TAG_INVOKE_DYNAMIC = 18; + + /** The {@linkplain #tag tag} for {@link LongEntry CONSTANT_Long} constant kind. */ + int TAG_LONG = 5; + + /** The {@linkplain #tag tag} for {@link MethodHandleEntry CONSTANT_MethodHandle} constant kind. */ + int TAG_METHOD_HANDLE = 15; + + /** The {@linkplain #tag tag} for {@link MethodRefEntry CONSTANT_Methodref} constant kind. */ + int TAG_METHODREF = 10; + + /** The {@linkplain #tag tag} for {@link MethodTypeEntry CONSTANT_MethodType} constant kind. */ + int TAG_METHOD_TYPE = 16; + + /** The {@linkplain #tag tag} for {@link ModuleEntry CONSTANT_Module} constant kind. */ + int TAG_MODULE = 19; + + /** The {@linkplain #tag tag} for {@link NameAndTypeEntry CONSTANT_NameAndType} constant kind. */ + int TAG_NAME_AND_TYPE = 12; + + /** The {@linkplain #tag tag} for {@link PackageEntry CONSTANT_Package} constant kind. */ + int TAG_PACKAGE = 20; + + /** The {@linkplain #tag tag} for {@link StringEntry CONSTANT_String} constant kind. */ + int TAG_STRING = 8; + + /** The {@linkplain #tag tag} for {@link Utf8Entry CONSTANT_Utf8} constant kind. */ + int TAG_UTF8 = 1; + /** * {@return the constant pool this entry is from} */ @@ -45,6 +96,10 @@ public sealed interface PoolEntry /** * {@return the constant pool tag that describes the type of this entry} + * + * @apiNote + * {@code TAG_}-prefixed constants in this class, such as {@link #TAG_UTF8}, + * describe the possible return values of this method. */ byte tag(); diff --git a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java index 89a54caeaf2fe..fca3279cd2228 100644 --- a/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java +++ b/src/java.base/share/classes/java/lang/classfile/instruction/CharacterRange.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -29,6 +29,7 @@ import java.lang.classfile.CodeModel; import java.lang.classfile.Label; import java.lang.classfile.PseudoInstruction; +import java.lang.classfile.attribute.CharacterRangeInfo; import java.lang.classfile.attribute.CharacterRangeTableAttribute; import jdk.internal.classfile.impl.AbstractPseudoInstruction; import jdk.internal.classfile.impl.BoundCharacterRange; @@ -45,6 +46,34 @@ @PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API) public sealed interface CharacterRange extends PseudoInstruction permits AbstractPseudoInstruction.UnboundCharacterRange, BoundCharacterRange { + + /** The bit mask of STATEMENT {@link CharacterRangeInfo} kind. */ + int FLAG_STATEMENT = 0x0001; + + /** The bit mask of BLOCK {@link CharacterRangeInfo} kind. */ + int FLAG_BLOCK = 0x0002; + + /** The bit mask of ASSIGNMENT {@link CharacterRangeInfo} kind. */ + int FLAG_ASSIGNMENT = 0x0004; + + /** The bit mask of FLOW_CONTROLLER {@link CharacterRangeInfo} kind. */ + int FLAG_FLOW_CONTROLLER = 0x0008; + + /** The bit mask of FLOW_TARGET {@link CharacterRangeInfo} kind. */ + int FLAG_FLOW_TARGET = 0x0010; + + /** The bit mask of INVOKE {@link CharacterRangeInfo} kind. */ + int FLAG_INVOKE = 0x0020; + + /** The bit mask of CREATE {@link CharacterRangeInfo} kind. */ + int FLAG_CREATE = 0x0040; + + /** The bit mask of BRANCH_TRUE {@link CharacterRangeInfo} kind. */ + int FLAG_BRANCH_TRUE = 0x0080; + + /** The bit mask of BRANCH_FALSE {@link CharacterRangeInfo} kind. */ + int FLAG_BRANCH_FALSE = 0x0100; + /** * {@return the start of the instruction range} */ @@ -75,15 +104,15 @@ public sealed interface CharacterRange extends PseudoInstruction * A flags word, indicating the kind of range. Multiple flag bits * may be set. Valid flags include: *
      - *
    • {@link java.lang.classfile.ClassFile#CRT_STATEMENT} - *
    • {@link java.lang.classfile.ClassFile#CRT_BLOCK} - *
    • {@link java.lang.classfile.ClassFile#CRT_ASSIGNMENT} - *
    • {@link java.lang.classfile.ClassFile#CRT_FLOW_CONTROLLER} - *
    • {@link java.lang.classfile.ClassFile#CRT_FLOW_TARGET} - *
    • {@link java.lang.classfile.ClassFile#CRT_INVOKE} - *
    • {@link java.lang.classfile.ClassFile#CRT_CREATE} - *
    • {@link java.lang.classfile.ClassFile#CRT_BRANCH_TRUE} - *
    • {@link java.lang.classfile.ClassFile#CRT_BRANCH_FALSE} + *
    • {@link #FLAG_STATEMENT} + *
    • {@link #FLAG_BLOCK} + *
    • {@link #FLAG_ASSIGNMENT} + *
    • {@link #FLAG_FLOW_CONTROLLER} + *
    • {@link #FLAG_FLOW_TARGET} + *
    • {@link #FLAG_INVOKE} + *
    • {@link #FLAG_CREATE} + *
    • {@link #FLAG_BRANCH_TRUE} + *
    • {@link #FLAG_BRANCH_FALSE} *
    * * @see java.lang.classfile.attribute.CharacterRangeInfo#flags() diff --git a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html index c680c0d2745a5..9f3ad156727a0 100644 --- a/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html +++ b/src/java.base/share/classes/java/lang/doc-files/threadPrimitiveDeprecation.html @@ -71,7 +71,7 @@

    What should I use instead of Thread.stop?

    communication of the stop-request, the variable must be volatile (or access to the variable must be synchronized).

    -

    For example, suppose your applet contains the following +

    For example, suppose your application contains the following start, stop and run methods:

    @@ -92,12 +92,12 @@ 

    What should I use instead of Thread.stop?

    Thread.sleep(interval); } catch (InterruptedException e){ } - repaint(); + blink(); } }
    You can avoid the use of Thread.stop by replacing the -applet's stop and run methods with: +application's stop and run methods with:
         private volatile Thread blinker;
     
    @@ -112,7 +112,7 @@ 

    What should I use instead of Thread.stop?

    Thread.sleep(interval); } catch (InterruptedException e){ } - repaint(); + blink(); } }
    diff --git a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java index 6031b55a107b2..4a905a3030b9a 100644 --- a/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java +++ b/src/java.base/share/classes/java/lang/invoke/InvokerBytecodeGenerator.java @@ -1645,7 +1645,7 @@ private void bogusMethod(ClassBuilder clb, Object os) { clb.withMethodBody("dummy", MTD_void, ACC_STATIC, new Consumer<>() { @Override public void accept(CodeBuilder cob) { - cob.loadConstant(os.toString()); + cob.ldc(os.toString()); cob.pop(); cob.return_(); } diff --git a/src/java.base/share/classes/java/lang/invoke/Invokers.java b/src/java.base/share/classes/java/lang/invoke/Invokers.java index 1f4314f5421d2..9990370ae25b6 100644 --- a/src/java.base/share/classes/java/lang/invoke/Invokers.java +++ b/src/java.base/share/classes/java/lang/invoke/Invokers.java @@ -25,6 +25,7 @@ package java.lang.invoke; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.annotation.DontInline; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Hidden; @@ -681,16 +682,9 @@ private static NamedFunction getNamedFunction(String name, MethodType type) } private static class Lazy { - private static final MethodHandle MH_asSpreader; - - static { - try { - MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader", - MethodType.methodType(MethodHandle.class, Class.class, int.class)); - } catch (ReflectiveOperationException ex) { - throw newInternalError(ex); - } - } + private static final MethodHandle MH_asSpreader = MhUtil.findVirtual( + IMPL_LOOKUP, MethodHandle.class, "asSpreader", + MethodType.methodType(MethodHandle.class, Class.class, int.class)); } static { diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java index edcecce37e05d..104248c27e61a 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandle.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandle.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -1879,8 +1879,7 @@ void updateForm(Function updater) { if (oldForm != newForm) { assert (newForm.customized == null || newForm.customized == this); newForm.prepare(); // as in MethodHandle. - UNSAFE.putReference(this, FORM_OFFSET, newForm); - UNSAFE.fullFence(); + UNSAFE.putReferenceRelease(this, FORM_OFFSET, newForm); // properly publish newForm } } finally { updateInProgress = false; diff --git a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java index 6a73266ae80a4..9e292373f9caf 100644 --- a/src/java.base/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/java.base/share/classes/java/lang/invoke/MethodHandles.java @@ -39,7 +39,9 @@ import sun.reflect.misc.ReflectUtil; import sun.security.util.SecurityConstants; +import java.lang.classfile.ClassFile; import java.lang.classfile.ClassModel; +import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.invoke.LambdaForm.BasicType; import java.lang.invoke.MethodHandleImpl.Intrinsic; @@ -2242,85 +2244,70 @@ private static ClassFileDumper defaultDumper() { private static final ClassFileDumper DEFAULT_DUMPER = ClassFileDumper.getInstance( "jdk.invoke.MethodHandle.dumpClassFiles", "DUMP_CLASS_FILES"); - static class ClassFile { - final String name; // internal name - final int accessFlags; - final byte[] bytes; - ClassFile(String name, int accessFlags, byte[] bytes) { - this.name = name; - this.accessFlags = accessFlags; - this.bytes = bytes; + /** + * This method checks the class file version and the structure of `this_class`. + * and checks if the bytes is a class or interface (ACC_MODULE flag not set) + * that is in the named package. + * + * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags + * or the class is not in the given package name. + */ + static String validateAndFindInternalName(byte[] bytes, String pkgName) { + int magic = readInt(bytes, 0); + if (magic != ClassFile.MAGIC_NUMBER) { + throw new ClassFormatError("Incompatible magic value: " + magic); } + // We have to read major and minor this way as ClassFile API throws IAE + // yet we want distinct ClassFormatError and UnsupportedClassVersionError + int minor = readUnsignedShort(bytes, 4); + int major = readUnsignedShort(bytes, 6); - static ClassFile newInstanceNoCheck(String name, byte[] bytes) { - return new ClassFile(name, 0, bytes); + if (!VM.isSupportedClassFileVersion(major, minor)) { + throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); } - /** - * This method checks the class file version and the structure of `this_class`. - * and checks if the bytes is a class or interface (ACC_MODULE flag not set) - * that is in the named package. - * - * @throws IllegalArgumentException if ACC_MODULE flag is set in access flags - * or the class is not in the given package name. - */ - static ClassFile newInstance(byte[] bytes, String pkgName) { - var cf = readClassFile(bytes); - - // check if it's in the named package - int index = cf.name.lastIndexOf('/'); - String pn = (index == -1) ? "" : cf.name.substring(0, index).replace('/', '.'); - if (!pn.equals(pkgName)) { - throw newIllegalArgumentException(cf.name + " not in same package as lookup class"); - } - return cf; + String name; + ClassDesc sym; + int accessFlags; + try { + ClassModel cm = ClassFile.of().parse(bytes); + var thisClass = cm.thisClass(); + name = thisClass.asInternalName(); + sym = thisClass.asSymbol(); + accessFlags = cm.flags().flagsMask(); + } catch (IllegalArgumentException e) { + ClassFormatError cfe = new ClassFormatError(); + cfe.initCause(e); + throw cfe; + } + // must be a class or interface + if ((accessFlags & ACC_MODULE) != 0) { + throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); } - private static ClassFile readClassFile(byte[] bytes) { - int magic = readInt(bytes, 0); - if (magic != 0xCAFEBABE) { - throw new ClassFormatError("Incompatible magic value: " + magic); - } - int minor = readUnsignedShort(bytes, 4); - int major = readUnsignedShort(bytes, 6); - if (!VM.isSupportedClassFileVersion(major, minor)) { - throw new UnsupportedClassVersionError("Unsupported class file version " + major + "." + minor); - } - - String name; - int accessFlags; - try { - ClassModel cm = java.lang.classfile.ClassFile.of().parse(bytes); - name = cm.thisClass().asInternalName(); - accessFlags = cm.flags().flagsMask(); - } catch (IllegalArgumentException e) { - ClassFormatError cfe = new ClassFormatError(); - cfe.initCause(e); - throw cfe; - } - // must be a class or interface - if ((accessFlags & ACC_MODULE) != 0) { - throw newIllegalArgumentException("Not a class or interface: ACC_MODULE flag is set"); - } - return new ClassFile(name, accessFlags, bytes); + String pn = sym.packageName(); + if (!pn.equals(pkgName)) { + throw newIllegalArgumentException(name + " not in same package as lookup class"); } - private static int readInt(byte[] bytes, int offset) { - if ((offset+4) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 24) - | ((bytes[offset + 1] & 0xFF) << 16) - | ((bytes[offset + 2] & 0xFF) << 8) - | (bytes[offset + 3] & 0xFF); + return name; + } + + private static int readInt(byte[] bytes, int offset) { + if ((offset + 4) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 24) + | ((bytes[offset + 1] & 0xFF) << 16) + | ((bytes[offset + 2] & 0xFF) << 8) + | (bytes[offset + 3] & 0xFF); + } - private static int readUnsignedShort(byte[] bytes, int offset) { - if ((offset+2) > bytes.length) { - throw new ClassFormatError("Invalid ClassFile structure"); - } - return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); + private static int readUnsignedShort(byte[] bytes, int offset) { + if ((offset+2) > bytes.length) { + throw new ClassFormatError("Invalid ClassFile structure"); } + return ((bytes[offset] & 0xFF) << 8) | (bytes[offset + 1] & 0xFF); } /* @@ -2334,23 +2321,22 @@ private static int readUnsignedShort(byte[] bytes, int offset) { * {@code bytes} denotes a class in a different package than the lookup class */ private ClassDefiner makeClassDefiner(byte[] bytes) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, defaultDumper()); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, defaultDumper()); } /** * Returns a ClassDefiner that creates a {@code Class} object of a normal class * from the given bytes. No package name check on the given bytes. * - * @param name internal name + * @param internalName internal name * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a normal class of the given bytes. */ - ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { // skip package name validation - ClassFile cf = ClassFile.newInstanceNoCheck(name, bytes); - return new ClassDefiner(this, cf, STRONG_LOADER_LINK, dumper); + return new ClassDefiner(this, internalName, bytes, STRONG_LOADER_LINK, dumper); } /** @@ -2368,8 +2354,8 @@ ClassDefiner makeClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) * {@code bytes} denotes a class in a different package than the lookup class */ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, false, dumper, 0); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** @@ -2391,51 +2377,53 @@ ClassDefiner makeHiddenClassDefiner(byte[] bytes, ClassFileDumper dumper) { private ClassDefiner makeHiddenClassDefiner(byte[] bytes, boolean accessVmAnnotations, int flags) { - ClassFile cf = ClassFile.newInstance(bytes, lookupClass().getPackageName()); - return makeHiddenClassDefiner(cf, accessVmAnnotations, defaultDumper(), flags); + var internalName = validateAndFindInternalName(bytes, lookupClass().getPackageName()); + return makeHiddenClassDefiner(internalName, bytes, accessVmAnnotations, defaultDumper(), flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, 0); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, 0); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given bytes and the given options. No package name check on the given bytes. * - * @param name internal name that specifies the prefix of the hidden class + * @param internalName internal name that specifies the prefix of the hidden class * @param bytes class bytes * @param flags class options flag mask * @param dumper dumper to write the given bytes to the dumper's output directory * @return ClassDefiner that defines a hidden class of the given bytes and options. */ - ClassDefiner makeHiddenClassDefiner(String name, byte[] bytes, ClassFileDumper dumper, int flags) { + ClassDefiner makeHiddenClassDefiner(String internalName, byte[] bytes, ClassFileDumper dumper, int flags) { Objects.requireNonNull(dumper); // skip name and access flags validation - return makeHiddenClassDefiner(ClassFile.newInstanceNoCheck(name, bytes), false, dumper, flags); + return makeHiddenClassDefiner(internalName, bytes, false, dumper, flags); } /** * Returns a ClassDefiner that creates a {@code Class} object of a hidden class * from the given class file and options. * - * @param cf ClassFile + * @param internalName internal name + * @param bytes Class byte array * @param flags class option flag mask * @param accessVmAnnotations true to give the hidden class access to VM annotations * @param dumper dumper to write the given bytes to the dumper's output directory */ - private ClassDefiner makeHiddenClassDefiner(ClassFile cf, + private ClassDefiner makeHiddenClassDefiner(String internalName, + byte[] bytes, boolean accessVmAnnotations, ClassFileDumper dumper, int flags) { @@ -2446,27 +2434,12 @@ private ClassDefiner makeHiddenClassDefiner(ClassFile cf, flags |= ACCESS_VM_ANNOTATIONS; } - return new ClassDefiner(this, cf, flags, dumper); + return new ClassDefiner(this, internalName, bytes, flags, dumper); } - static class ClassDefiner { - private final Lookup lookup; - private final String name; // internal name - private final byte[] bytes; - private final int classFlags; - private final ClassFileDumper dumper; - - private ClassDefiner(Lookup lookup, ClassFile cf, int flags, ClassFileDumper dumper) { - assert ((flags & HIDDEN_CLASS) != 0 || (flags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); - this.lookup = lookup; - this.bytes = cf.bytes; - this.name = cf.name; - this.classFlags = flags; - this.dumper = dumper; - } - - String internalName() { - return name; + record ClassDefiner(Lookup lookup, String internalName, byte[] bytes, int classFlags, ClassFileDumper dumper) { + ClassDefiner { + assert ((classFlags & HIDDEN_CLASS) != 0 || (classFlags & STRONG_LOADER_LINK) == STRONG_LOADER_LINK); } Class defineClass(boolean initialize) { @@ -2495,7 +2468,7 @@ Class defineClass(boolean initialize, Object classData) { Class c = null; try { c = SharedSecrets.getJavaLangAccess() - .defineClass(loader, lookupClass, name, bytes, pd, initialize, classFlags, classData); + .defineClass(loader, lookupClass, internalName, bytes, pd, initialize, classFlags, classData); assert !isNestmate() || c.getNestHost() == lookupClass.getNestHost(); return c; } finally { diff --git a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java index 50ba77d8f96f9..65872e360a73f 100644 --- a/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java +++ b/src/java.base/share/classes/java/lang/invoke/MutableCallSite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -26,7 +26,8 @@ package java.lang.invoke; import java.util.Objects; -import java.util.concurrent.atomic.AtomicInteger; + +import static java.lang.invoke.MethodHandleStatics.UNSAFE; /** * A {@code MutableCallSite} is a {@link CallSite} whose target variable @@ -274,11 +275,10 @@ public final MethodHandle dynamicInvoker() { */ public static void syncAll(MutableCallSite[] sites) { if (sites.length == 0) return; - STORE_BARRIER.lazySet(0); + UNSAFE.storeFence(); for (MutableCallSite site : sites) { Objects.requireNonNull(site); // trigger NPE on first null } // FIXME: NYI } - private static final AtomicInteger STORE_BARRIER = new AtomicInteger(); } diff --git a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java index 2e56d03c6ad89..abdcaf5ae1fa2 100644 --- a/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java +++ b/src/java.base/share/classes/java/lang/reflect/ProxyGenerator.java @@ -114,11 +114,18 @@ final class ProxyGenerator { private static final Method OBJECT_EQUALS_METHOD; private static final Method OBJECT_TO_STRING_METHOD; + private static final String OBJECT_HASH_CODE_SIG; + private static final String OBJECT_EQUALS_SIG; + private static final String OBJECT_TO_STRING_SIG; + static { try { OBJECT_HASH_CODE_METHOD = Object.class.getMethod("hashCode"); + OBJECT_HASH_CODE_SIG = OBJECT_HASH_CODE_METHOD.toShortSignature(); OBJECT_EQUALS_METHOD = Object.class.getMethod("equals", Object.class); + OBJECT_EQUALS_SIG = OBJECT_EQUALS_METHOD.toShortSignature(); OBJECT_TO_STRING_METHOD = Object.class.getMethod("toString"); + OBJECT_TO_STRING_SIG = OBJECT_TO_STRING_METHOD.toShortSignature(); } catch (NoSuchMethodException e) { throw new NoSuchMethodError(e.getMessage()); } @@ -446,9 +453,9 @@ private byte[] generateClassFile() { * java.lang.Object take precedence over duplicate methods in the * proxy interfaces. */ - addProxyMethod(new ProxyMethod(OBJECT_HASH_CODE_METHOD, "m0")); - addProxyMethod(new ProxyMethod(OBJECT_EQUALS_METHOD, "m1")); - addProxyMethod(new ProxyMethod(OBJECT_TO_STRING_METHOD, "m2")); + addProxyMethod(new ProxyMethod(OBJECT_HASH_CODE_METHOD, OBJECT_HASH_CODE_SIG, "m0")); + addProxyMethod(new ProxyMethod(OBJECT_EQUALS_METHOD, OBJECT_EQUALS_SIG, "m1")); + addProxyMethod(new ProxyMethod(OBJECT_TO_STRING_METHOD, OBJECT_TO_STRING_SIG, "m2")); /* * Accumulate all of the methods from the proxy interfaces. @@ -526,7 +533,7 @@ private void addProxyMethod(Method m, Class fromClass) { return; } } - sigmethods.add(new ProxyMethod(m, sig, m.getSharedParameterTypes(), returnType, + sigmethods.add(new ProxyMethod(m, sig, returnType, exceptionTypes, fromClass, "m" + proxyMethodCount++)); } @@ -617,11 +624,11 @@ private void generateLookupAccessor(ClassBuilder clb) { Label failLabel = cob.newLabel(); ClassEntry mhl = cp.classEntry(CD_MethodHandles_Lookup); ClassEntry iae = cp.classEntry(CD_IllegalAccessException); - cob.aload(cob.parameterSlot(0)) + cob.aload(0) .invokevirtual(cp.methodRefEntry(mhl, cp.nameAndTypeEntry("lookupClass", MTD_Class))) .ldc(proxyCE) .if_acmpne(failLabel) - .aload(cob.parameterSlot(0)) + .aload(0) .invokevirtual(cp.methodRefEntry(mhl, cp.nameAndTypeEntry("hasFullPrivilegeAccess", MTD_boolean))) .ifeq(failLabel) .invokestatic(CD_MethodHandles, "lookup", MTD_MethodHandles$Lookup) @@ -629,7 +636,7 @@ private void generateLookupAccessor(ClassBuilder clb) { .labelBinding(failLabel) .new_(iae) .dup() - .aload(cob.parameterSlot(0)) + .aload(0) .invokevirtual(cp.methodRefEntry(mhl, cp.nameAndTypeEntry("toString", MTD_String))) .invokespecial(cp.methodRefEntry(iae, exInit)) .athrow() @@ -650,18 +657,16 @@ private class ProxyMethod { private final Method method; private final String shortSignature; private final Class fromClass; - private final Class[] parameterTypes; private final Class returnType; private final String methodFieldName; private Class[] exceptionTypes; private final FieldRefEntry methodField; - private ProxyMethod(Method method, String sig, Class[] parameterTypes, + private ProxyMethod(Method method, String sig, Class returnType, Class[] exceptionTypes, Class fromClass, String methodFieldName) { this.method = method; this.shortSignature = sig; - this.parameterTypes = parameterTypes; this.returnType = returnType; this.exceptionTypes = exceptionTypes; this.fromClass = fromClass; @@ -670,14 +675,17 @@ private ProxyMethod(Method method, String sig, Class[] parameterTypes, cp.nameAndTypeEntry(methodFieldName, CD_Method)); } + private Class[] parameterTypes() { + return method.getSharedParameterTypes(); + } + /** * Create a new specific ProxyMethod with a specific field name * * @param method The method for which to create a proxy */ - private ProxyMethod(Method method, String methodFieldName) { - this(method, method.toShortSignature(), - method.getSharedParameterTypes(), method.getReturnType(), + private ProxyMethod(Method method, String sig, String methodFieldName) { + this(method, sig, method.getReturnType(), method.getSharedExceptionTypes(), method.getDeclaringClass(), methodFieldName); } @@ -685,17 +693,18 @@ private ProxyMethod(Method method, String methodFieldName) { * Generate this method, including the code and exception table entry. */ private void generateMethod(ClassBuilder clb) { - var desc = methodTypeDesc(returnType, parameterTypes); + var desc = methodTypeDesc(returnType, parameterTypes()); int accessFlags = (method.isVarArgs()) ? ACC_VARARGS | ACC_PUBLIC | ACC_FINAL : ACC_PUBLIC | ACC_FINAL; - var catchList = computeUniqueCatchList(exceptionTypes); clb.withMethod(method.getName(), desc, accessFlags, mb -> mb.with(ExceptionsAttribute.of(toClassEntries(cp, List.of(exceptionTypes)))) .withCode(cob -> { + var catchList = computeUniqueCatchList(exceptionTypes); cob.aload(cob.receiverSlot()) .getfield(handlerField) .aload(cob.receiverSlot()) .getstatic(methodField); + Class[] parameterTypes = parameterTypes(); if (parameterTypes.length > 0) { // Create an array and fill with the parameters converting primitives to wrappers cob.loadConstant(parameterTypes.length) @@ -784,6 +793,7 @@ private void codeFieldInitialization(CodeBuilder cob) { var cp = cob.constantPool(); codeClassForName(cob, fromClass); + Class[] parameterTypes = parameterTypes(); cob.ldc(method.getName()) .loadConstant(parameterTypes.length) .anewarray(classCE); @@ -817,10 +827,14 @@ private void codeFieldInitialization(CodeBuilder cob) { * loader is anticipated at local variable index 0. */ private void codeClassForName(CodeBuilder cob, Class cl) { - cob.ldc(cl.getName()) - .iconst_0() // false - .aload(0)// classLoader - .invokestatic(classForName); + if (cl == Object.class) { + cob.ldc(objectCE); + } else { + cob.ldc(cl.getName()) + .iconst_0() // false + .aload(0)// classLoader + .invokestatic(classForName); + } } @Override diff --git a/src/java.base/share/classes/java/net/HttpURLConnection.java b/src/java.base/share/classes/java/net/HttpURLConnection.java index b405fb10a1655..625fd30424eea 100644 --- a/src/java.base/share/classes/java/net/HttpURLConnection.java +++ b/src/java.base/share/classes/java/net/HttpURLConnection.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -373,8 +373,7 @@ protected HttpURLConnection (URL u) { /** * Sets whether HTTP redirects (requests with response code 3xx) should - * be automatically followed by this class. True by default. Applets - * cannot change this variable. + * be automatically followed by this class. True by default. *

    * If there is a security manager, this method first calls * the security manager's {@code checkSetFactory} method diff --git a/src/java.base/share/classes/java/net/Socket.java b/src/java.base/share/classes/java/net/Socket.java index 23c225fbb2d29..309fa7a80d099 100644 --- a/src/java.base/share/classes/java/net/Socket.java +++ b/src/java.base/share/classes/java/net/Socket.java @@ -27,6 +27,7 @@ import jdk.internal.event.SocketReadEvent; import jdk.internal.event.SocketWriteEvent; +import jdk.internal.invoke.MhUtil; import sun.security.util.SecurityConstants; import java.io.InputStream; @@ -102,14 +103,10 @@ public class Socket implements java.io.Closeable { private static final VarHandle STATE, IN, OUT; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - STATE = l.findVarHandle(Socket.class, "state", int.class); - IN = l.findVarHandle(Socket.class, "in", InputStream.class); - OUT = l.findVarHandle(Socket.class, "out", OutputStream.class); - } catch (Exception e) { - throw new InternalError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + STATE = MhUtil.findVarHandle(l, "state", int.class); + IN = MhUtil.findVarHandle(l, "in", InputStream.class); + OUT = MhUtil.findVarHandle(l, "out", OutputStream.class); } // the underlying SocketImpl, may be null, may be swapped when connecting diff --git a/src/java.base/share/classes/java/nio/channels/SelectionKey.java b/src/java.base/share/classes/java/nio/channels/SelectionKey.java index ca6df2a7aa054..79029e6365353 100644 --- a/src/java.base/share/classes/java/nio/channels/SelectionKey.java +++ b/src/java.base/share/classes/java/nio/channels/SelectionKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -25,6 +25,8 @@ package java.nio.channels; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -429,15 +431,9 @@ public final boolean isAcceptable() { // -- Attachments -- - private static final VarHandle ATTACHMENT; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - ATTACHMENT = l.findVarHandle(SelectionKey.class, "attachment", Object.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle ATTACHMENT = MhUtil.findVarHandle( + MethodHandles.lookup(), "attachment", Object.class); + private volatile Object attachment; /** diff --git a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectionKey.java b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectionKey.java index 0a79ca321dd33..3005fc9522c64 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectionKey.java +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelectionKey.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -30,6 +30,7 @@ import java.nio.channels.SelectionKey; import java.nio.channels.Selector; +import jdk.internal.invoke.MhUtil; import sun.nio.ch.SelectionKeyImpl; import sun.nio.ch.SelectorImpl; @@ -46,15 +47,8 @@ public abstract class AbstractSelectionKey extends SelectionKey { - private static final VarHandle INVALID; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - INVALID = l.findVarHandle(AbstractSelectionKey.class, "invalid", boolean.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle INVALID = MhUtil.findVarHandle( + MethodHandles.lookup(), "invalid", boolean.class); /** * Initializes a new instance of this class. diff --git a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java index 7ea5f89221834..71dc8620eb804 100644 --- a/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java +++ b/src/java.base/share/classes/java/nio/channels/spi/AbstractSelector.java @@ -32,6 +32,8 @@ import java.nio.channels.Selector; import java.util.HashSet; import java.util.Set; + +import jdk.internal.invoke.MhUtil; import sun.nio.ch.Interruptible; import sun.nio.ch.SelectorImpl; @@ -72,15 +74,9 @@ public abstract class AbstractSelector extends Selector { - private static final VarHandle CLOSED; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - CLOSED = l.findVarHandle(AbstractSelector.class, "closed", boolean.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle CLOSED = MhUtil.findVarHandle( + MethodHandles.lookup(), "closed", boolean.class); + private volatile boolean closed; // The provider that created this selector diff --git a/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java b/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java index 87ff0d07854ef..11d36ee242d56 100644 --- a/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java +++ b/src/java.base/share/classes/java/nio/charset/spi/CharsetProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -36,7 +36,7 @@ * zero-argument constructor and some number of associated charset * implementation classes. Charset providers may be installed in an instance * of the Java platform as extensions. Providers may also be made available by - * adding them to the applet or application class path or by some other + * adding them to the application class path or by some other * platform-specific means. Charset providers are looked up via the current * thread's {@link java.lang.Thread#getContextClassLoader() context class * loader}. diff --git a/src/java.base/share/classes/java/security/Policy.java b/src/java.base/share/classes/java/security/Policy.java index 838366b7e3862..37f7cc3d9a686 100644 --- a/src/java.base/share/classes/java/security/Policy.java +++ b/src/java.base/share/classes/java/security/Policy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -896,5 +896,15 @@ public UnsupportedEmptyCollection() { @Override public Enumeration elements() { return perms.elements(); } + + /** + * If this object is readonly, no new objects can be added to it using {@code add}. + * + * @return {@code true} if this object is marked as readonly, {@code false} otherwise. + */ + @Override + public boolean isReadOnly() { + return perms.isReadOnly(); + } } } diff --git a/src/java.base/share/classes/java/security/Security.java b/src/java.base/share/classes/java/security/Security.java index 0cdd22340dfbf..6628b717eb073 100644 --- a/src/java.base/share/classes/java/security/Security.java +++ b/src/java.base/share/classes/java/security/Security.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 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 @@ -25,22 +25,39 @@ package java.security; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; import java.net.MalformedURLException; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import java.io.*; +import java.net.URI; import java.net.URL; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import jdk.internal.access.JavaSecurityPropertiesAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.event.EventHelper; import jdk.internal.event.SecurityPropertyModificationEvent; -import jdk.internal.access.SharedSecrets; import jdk.internal.util.StaticProperty; +import sun.security.jca.GetInstance; +import sun.security.jca.ProviderList; +import sun.security.jca.Providers; import sun.security.util.Debug; import sun.security.util.PropertyExpander; -import sun.security.jca.*; - /** *

    This class centralizes all security properties and common security * methods. One of its primary uses is to manage providers. @@ -63,7 +80,17 @@ public final class Security { Debug.getInstance("properties"); /* The java.security properties */ - private static Properties props; + private static final Properties props = new Properties() { + @Override + public synchronized Object put(Object key, Object val) { + if (key instanceof String strKey && val instanceof String strVal && + SecPropLoader.isInclude(strKey)) { + SecPropLoader.loadInclude(strVal); + return null; + } + return super.put(key, val); + } + }; /* cache a copy for recording purposes */ private static Properties initialSecurityProperties; @@ -74,11 +101,220 @@ private static class ProviderProperty { Provider provider; } + private static final class SecPropLoader { + private enum LoadingMode {OVERRIDE, APPEND} + + private static final String OVERRIDE_SEC_PROP = + "security.overridePropertiesFile"; + + private static final String EXTRA_SYS_PROP = + "java.security.properties"; + + private static Path currentPath; + + private static final Set activePaths = new HashSet<>(); + + static void loadAll() { + // first load the master properties file to + // determine the value of OVERRIDE_SEC_PROP + loadMaster(); + loadExtra(); + } + + static boolean isInclude(String key) { + return "include".equals(key); + } + + static void checkReservedKey(String key) + throws IllegalArgumentException { + if (isInclude(key)) { + throw new IllegalArgumentException("Key '" + key + + "' is reserved and cannot be used as a " + + "Security property name."); + } + } + + private static void loadMaster() { + try { + loadFromPath(Path.of(StaticProperty.javaHome(), "conf", + "security", "java.security"), LoadingMode.APPEND); + } catch (IOException e) { + throw new InternalError("Error loading java.security file", e); + } + } + + private static void loadExtra() { + if ("true".equalsIgnoreCase(props.getProperty(OVERRIDE_SEC_PROP))) { + String propFile = System.getProperty(EXTRA_SYS_PROP); + if (propFile != null) { + LoadingMode mode = LoadingMode.APPEND; + if (propFile.startsWith("=")) { + mode = LoadingMode.OVERRIDE; + propFile = propFile.substring(1); + } + try { + loadExtraHelper(propFile, mode); + } catch (Exception e) { + if (sdebug != null) { + sdebug.println("unable to load security " + + "properties from " + propFile); + e.printStackTrace(); + } + } + } + } + } + + private static void loadExtraHelper(String propFile, LoadingMode mode) + throws Exception { + propFile = PropertyExpander.expand(propFile); + if (propFile.isEmpty()) { + throw new IOException("Empty extra properties file path"); + } + + // Try to interpret propFile as a path + Exception error; + if ((error = loadExtraFromPath(propFile, mode)) == null) { + return; + } + + // Try to interpret propFile as a file URL + URI uri = null; + try { + uri = new URI(propFile); + } catch (Exception ignore) {} + if (uri != null && "file".equalsIgnoreCase(uri.getScheme()) && + (error = loadExtraFromFileUrl(uri, mode)) == null) { + return; + } + + // Try to interpret propFile as a URL + URL url; + try { + url = newURL(propFile); + } catch (MalformedURLException ignore) { + // URL has no scheme: previous error is more accurate + throw error; + } + loadFromUrl(url, mode); + } + + private static Exception loadExtraFromPath(String propFile, + LoadingMode mode) throws Exception { + Path path; + try { + path = Path.of(propFile); + if (!Files.exists(path)) { + return new FileNotFoundException(propFile); + } + } catch (InvalidPathException e) { + return e; + } + loadFromPath(path, mode); + return null; + } + + + private static Exception loadExtraFromFileUrl(URI uri, LoadingMode mode) + throws Exception { + Path path; + try { + path = Path.of(uri); + } catch (Exception e) { + return e; + } + loadFromPath(path, mode); + return null; + } + + private static void reset(LoadingMode mode) { + if (mode == LoadingMode.OVERRIDE) { + if (sdebug != null) { + sdebug.println( + "overriding other security properties files!"); + } + props.clear(); + } + } + + static void loadInclude(String propFile) { + String expPropFile = PropertyExpander.expandNonStrict(propFile); + if (sdebug != null) { + sdebug.println("processing include: '" + propFile + "'" + + (propFile.equals(expPropFile) ? "" : + " (expanded to '" + expPropFile + "')")); + } + try { + Path path = Path.of(expPropFile); + if (!path.isAbsolute()) { + if (currentPath == null) { + throw new InternalError("Cannot resolve '" + + expPropFile + "' relative path when included " + + "from a non-regular properties file " + + "(e.g. HTTP served file)"); + } + path = currentPath.resolveSibling(path); + } + loadFromPath(path, LoadingMode.APPEND); + } catch (IOException | InvalidPathException e) { + throw new InternalError("Unable to include '" + expPropFile + + "'", e); + } + } + + private static void loadFromPath(Path path, LoadingMode mode) + throws IOException { + boolean isRegularFile = Files.isRegularFile(path); + if (isRegularFile) { + path = path.toRealPath(); + } else if (Files.isDirectory(path)) { + throw new IOException("Is a directory"); + } else { + path = path.toAbsolutePath(); + } + if (activePaths.contains(path)) { + throw new InternalError("Cyclic include of '" + path + "'"); + } + try (InputStream is = Files.newInputStream(path)) { + reset(mode); + Path previousPath = currentPath; + currentPath = isRegularFile ? path : null; + activePaths.add(path); + try { + debugLoad(true, path); + props.load(is); + debugLoad(false, path); + } finally { + activePaths.remove(path); + currentPath = previousPath; + } + } + } + + private static void loadFromUrl(URL url, LoadingMode mode) + throws IOException { + try (InputStream is = url.openStream()) { + reset(mode); + debugLoad(true, url); + props.load(is); + debugLoad(false, url); + } + } + + private static void debugLoad(boolean start, Object source) { + if (sdebug != null) { + int level = activePaths.isEmpty() ? 1 : activePaths.size(); + sdebug.println((start ? + ">".repeat(level) + " starting to process " : + "<".repeat(level) + " finished processing ") + source); + } + } + } + static { // doPrivileged here because there are multiple // things in initialize that might require privs. - // (the FileInputStream call and the File.exists call, - // the securityPropFile call, etc) + // (the FileInputStream call and the File.exists call, etc) @SuppressWarnings("removal") var dummy = AccessController.doPrivileged((PrivilegedAction) () -> { initialize(); @@ -94,28 +330,7 @@ public Properties getInitialProperties() { } private static void initialize() { - props = new Properties(); - boolean overrideAll = false; - - // first load the system properties file - // to determine the value of security.overridePropertiesFile - File propFile = securityPropFile("java.security"); - boolean success = loadProps(propFile, null, false); - if (!success) { - throw new InternalError("Error loading java.security file"); - } - - if ("true".equalsIgnoreCase(props.getProperty - ("security.overridePropertiesFile"))) { - - String extraPropFile = System.getProperty - ("java.security.properties"); - if (extraPropFile != null && extraPropFile.startsWith("=")) { - overrideAll = true; - extraPropFile = extraPropFile.substring(1); - } - loadProps(null, extraPropFile, overrideAll); - } + SecPropLoader.loadAll(); initialSecurityProperties = (Properties) props.clone(); if (sdebug != null) { for (String key : props.stringPropertyNames()) { @@ -123,63 +338,6 @@ private static void initialize() { props.getProperty(key)); } } - - } - - private static boolean loadProps(File masterFile, String extraPropFile, boolean overrideAll) { - InputStream is = null; - try { - if (masterFile != null && masterFile.exists()) { - is = new FileInputStream(masterFile); - } else if (extraPropFile != null) { - extraPropFile = PropertyExpander.expand(extraPropFile); - File propFile = new File(extraPropFile); - URL propURL; - if (propFile.exists()) { - propURL = newURL - ("file:" + propFile.getCanonicalPath()); - } else { - propURL = newURL(extraPropFile); - } - - is = propURL.openStream(); - if (overrideAll) { - props = new Properties(); - if (sdebug != null) { - sdebug.println - ("overriding other security properties files!"); - } - } - } else { - // unexpected - return false; - } - props.load(is); - if (sdebug != null) { - // ExceptionInInitializerError if masterFile.getName() is - // called here (NPE!). Leave as is (and few lines down) - sdebug.println("reading security properties file: " + - masterFile == null ? extraPropFile : "java.security"); - } - return true; - } catch (IOException | PropertyExpander.ExpandException e) { - if (sdebug != null) { - sdebug.println("unable to load security properties from " + - masterFile == null ? extraPropFile : "java.security"); - e.printStackTrace(); - } - return false; - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException ioe) { - if (sdebug != null) { - sdebug.println("unable to close input stream"); - } - } - } - } } /** @@ -188,14 +346,6 @@ private static boolean loadProps(File masterFile, String extraPropFile, boolean private Security() { } - private static File securityPropFile(String filename) { - // maybe check for a system property which will specify where to - // look. Someday. - String sep = File.separator; - return new File(StaticProperty.javaHome() + sep + "conf" + sep + - "security" + sep + filename); - } - /** * Looks up providers, and returns the property (and its associated * provider) mapping the key, if any. @@ -714,17 +864,16 @@ static Object[] getImpl(String algorithm, String type, Provider provider, * denies * access to retrieve the specified security property value * @throws NullPointerException if key is {@code null} + * @throws IllegalArgumentException if key is reserved and cannot be + * used as a Security property name. Reserved keys are: + * "include". * * @see #setProperty * @see java.security.SecurityPermission */ public static String getProperty(String key) { - @SuppressWarnings("removal") - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new SecurityPermission("getProperty."+ - key)); - } + SecPropLoader.checkReservedKey(key); + check("getProperty." + key); String name = props.getProperty(key); if (name != null) name = name.trim(); // could be a class name with trailing ws @@ -749,11 +898,15 @@ public static String getProperty(String key) { * java.lang.SecurityManager#checkPermission} method * denies access to set the specified security property value * @throws NullPointerException if key or datum is {@code null} + * @throws IllegalArgumentException if key is reserved and cannot be + * used as a Security property name. Reserved keys are: + * "include". * * @see #getProperty * @see java.security.SecurityPermission */ public static void setProperty(String key, String datum) { + SecPropLoader.checkReservedKey(key); check("setProperty." + key); props.put(key, datum); invalidateSMCache(key); /* See below. */ diff --git a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java index 8adfd106eebb4..d690494405085 100644 --- a/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java +++ b/src/java.base/share/classes/java/util/concurrent/CompletableFuture.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.concurrent.locks.LockSupport; @@ -3079,14 +3081,10 @@ static final class MinimalStage extends CompletableFuture { private static final VarHandle STACK; private static final VarHandle NEXT; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - RESULT = l.findVarHandle(CompletableFuture.class, "result", Object.class); - STACK = l.findVarHandle(CompletableFuture.class, "stack", Completion.class); - NEXT = l.findVarHandle(Completion.class, "next", Completion.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + RESULT = MhUtil.findVarHandle(l, "result", Object.class); + STACK = MhUtil.findVarHandle(l, "stack", Completion.class); + NEXT = MhUtil.findVarHandle(l, Completion.class, "next", Completion.class); // Reduce the risk of rare disastrous classloading in first call to // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 diff --git a/src/java.base/share/classes/java/util/concurrent/Exchanger.java b/src/java.base/share/classes/java/util/concurrent/Exchanger.java index 8674ea9af39bc..75de69b3e5283 100644 --- a/src/java.base/share/classes/java/util/concurrent/Exchanger.java +++ b/src/java.base/share/classes/java/util/concurrent/Exchanger.java @@ -36,6 +36,8 @@ package java.util.concurrent; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.concurrent.locks.LockSupport; @@ -530,15 +532,11 @@ public V exchange(V x, long timeout, TimeUnit unit) private static final VarHandle ENTRY; private static final VarHandle AA; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - BOUND = l.findVarHandle(Exchanger.class, "bound", int.class); - MATCH = l.findVarHandle(Node.class, "match", Object.class); - ENTRY = l.findVarHandle(Slot.class, "entry", Node.class); - AA = MethodHandles.arrayElementVarHandle(Slot[].class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + BOUND = MhUtil.findVarHandle(l, "bound", int.class); + MATCH = MhUtil.findVarHandle(l, Node.class, "match", Object.class); + ENTRY = MhUtil.findVarHandle(l, Slot.class, "entry", Node.class); + AA = MethodHandles.arrayElementVarHandle(Slot[].class); } } diff --git a/src/java.base/share/classes/java/util/concurrent/FutureTask.java b/src/java.base/share/classes/java/util/concurrent/FutureTask.java index 627e69559c856..b905e71aeef95 100644 --- a/src/java.base/share/classes/java/util/concurrent/FutureTask.java +++ b/src/java.base/share/classes/java/util/concurrent/FutureTask.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.concurrent.locks.LockSupport; @@ -582,14 +584,10 @@ public String toString() { private static final VarHandle RUNNER; private static final VarHandle WAITERS; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - STATE = l.findVarHandle(FutureTask.class, "state", int.class); - RUNNER = l.findVarHandle(FutureTask.class, "runner", Thread.class); - WAITERS = l.findVarHandle(FutureTask.class, "waiters", WaitNode.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + STATE = MhUtil.findVarHandle(l, "state", int.class); + RUNNER = MhUtil.findVarHandle(l, "runner", Thread.class); + WAITERS = MhUtil.findVarHandle(l, "waiters", WaitNode.class); // Reduce the risk of rare disastrous classloading in first call to // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 diff --git a/src/java.base/share/classes/java/util/concurrent/Phaser.java b/src/java.base/share/classes/java/util/concurrent/Phaser.java index 22e2f663cb9a7..9cd2376d84714 100644 --- a/src/java.base/share/classes/java/util/concurrent/Phaser.java +++ b/src/java.base/share/classes/java/util/concurrent/Phaser.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.concurrent.atomic.AtomicReference; @@ -1137,15 +1139,9 @@ public boolean block() { } // VarHandle mechanics - private static final VarHandle STATE; + private static final VarHandle STATE = MhUtil.findVarHandle( + MethodHandles.lookup(), "state", long.class); static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - STATE = l.findVarHandle(Phaser.class, "state", long.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - // Reduce the risk of rare disastrous classloading in first call to // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 Class ensureLoaded = LockSupport.class; diff --git a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java index fdb0128b7a755..f51e356736dea 100644 --- a/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java +++ b/src/java.base/share/classes/java/util/concurrent/PriorityBlockingQueue.java @@ -53,6 +53,7 @@ import java.util.function.Consumer; import java.util.function.Predicate; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; import jdk.internal.util.ArraysSupport; /** @@ -1093,15 +1094,8 @@ public void forEach(Consumer action) { } // VarHandle mechanics - private static final VarHandle ALLOCATIONSPINLOCK; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - ALLOCATIONSPINLOCK = l.findVarHandle(PriorityBlockingQueue.class, - "allocationSpinLock", - int.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle ALLOCATIONSPINLOCK = + MhUtil.findVarHandle( + MethodHandles.lookup(), "allocationSpinLock", int.class); + } diff --git a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java index 31b4cd6c6a613..edb2708934d90 100644 --- a/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java +++ b/src/java.base/share/classes/java/util/concurrent/StructuredTaskScope.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -37,6 +37,7 @@ import java.util.function.Supplier; import jdk.internal.javac.PreviewFeature; import jdk.internal.misc.ThreadFlock; +import jdk.internal.invoke.MhUtil; /** * A basic API for structured concurrency. {@code StructuredTaskScope} supports @@ -990,13 +991,9 @@ public static final class ShutdownOnSuccess extends StructuredTaskScope { private static final VarHandle FIRST_RESULT; private static final VarHandle FIRST_EXCEPTION; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - FIRST_RESULT = l.findVarHandle(ShutdownOnSuccess.class, "firstResult", Object.class); - FIRST_EXCEPTION = l.findVarHandle(ShutdownOnSuccess.class, "firstException", Throwable.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + FIRST_RESULT = MhUtil.findVarHandle(l, "firstResult", Object.class); + FIRST_EXCEPTION = MhUtil.findVarHandle(l, "firstException", Throwable.class); } private volatile Object firstResult; private volatile Throwable firstException; @@ -1177,15 +1174,8 @@ public T result(Function esf) thro */ @PreviewFeature(feature = PreviewFeature.Feature.STRUCTURED_CONCURRENCY) public static final class ShutdownOnFailure extends StructuredTaskScope { - private static final VarHandle FIRST_EXCEPTION; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - FIRST_EXCEPTION = l.findVarHandle(ShutdownOnFailure.class, "firstException", Throwable.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle FIRST_EXCEPTION = + MhUtil.findVarHandle(MethodHandles.lookup(), "firstException", Throwable.class); private volatile Throwable firstException; /** diff --git a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java index b27c57114d620..a2fc3ac92bdbc 100644 --- a/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java +++ b/src/java.base/share/classes/java/util/concurrent/SubmissionPublisher.java @@ -35,6 +35,8 @@ package java.util.concurrent; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.ArrayList; @@ -1505,16 +1507,10 @@ else if (timed) static final VarHandle QA; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - CTL = l.findVarHandle(BufferedSubscription.class, "ctl", - int.class); - DEMAND = l.findVarHandle(BufferedSubscription.class, "demand", - long.class); - QA = MethodHandles.arrayElementVarHandle(Object[].class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + CTL = MhUtil.findVarHandle(l, "ctl", int.class); + DEMAND = MhUtil.findVarHandle(l, "demand", long.class); + QA = MethodHandles.arrayElementVarHandle(Object[].class); // Reduce the risk of rare disastrous classloading in first call to // LockSupport.park: https://bugs.openjdk.org/browse/JDK-8074773 diff --git a/src/java.base/share/classes/java/util/concurrent/ThreadPerTaskExecutor.java b/src/java.base/share/classes/java/util/concurrent/ThreadPerTaskExecutor.java index ca9ce08db7466..e98ece084c0df 100644 --- a/src/java.base/share/classes/java/util/concurrent/ThreadPerTaskExecutor.java +++ b/src/java.base/share/classes/java/util/concurrent/ThreadPerTaskExecutor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -38,6 +38,7 @@ import static java.util.concurrent.TimeUnit.NANOSECONDS; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.ThreadContainer; import jdk.internal.vm.ThreadContainers; @@ -48,15 +49,8 @@ class ThreadPerTaskExecutor extends ThreadContainer implements ExecutorService { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); private static final Permission MODIFY_THREAD = new RuntimePermission("modifyThread"); - private static final VarHandle STATE; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - STATE = l.findVarHandle(ThreadPerTaskExecutor.class, "state", int.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle STATE = MhUtil.findVarHandle( + MethodHandles.lookup(), "state", int.class); private final ThreadFactory factory; private final Set threads = ConcurrentHashMap.newKeySet(); @@ -506,14 +500,10 @@ private static class AnyResultHolder { private static final VarHandle EXCEPTION; private static final VarHandle EXCEPTION_COUNT; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - RESULT = l.findVarHandle(AnyResultHolder.class, "result", Object.class); - EXCEPTION = l.findVarHandle(AnyResultHolder.class, "exception", Throwable.class); - EXCEPTION_COUNT = l.findVarHandle(AnyResultHolder.class, "exceptionCount", int.class); - } catch (Exception e) { - throw new InternalError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + RESULT = MhUtil.findVarHandle(l, "result", Object.class); + EXCEPTION = MhUtil.findVarHandle(l, "exception", Throwable.class); + EXCEPTION_COUNT = MhUtil.findVarHandle(l, "exceptionCount", int.class); } private static final Object NULL = new Object(); diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java index c6671deaa2eb5..fb171e9c1d99f 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicBoolean.java @@ -35,6 +35,8 @@ package java.util.concurrent.atomic; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -50,15 +52,8 @@ */ public class AtomicBoolean implements java.io.Serializable { private static final long serialVersionUID = 4654671469794556979L; - private static final VarHandle VALUE; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - VALUE = l.findVarHandle(AtomicBoolean.class, "value", int.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle VALUE = MhUtil.findVarHandle( + MethodHandles.lookup(), "value", int.class); private volatile int value; diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java index 8e1727c8f1972..d74c3f2ef4f4f 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicMarkableReference.java @@ -35,6 +35,8 @@ package java.util.concurrent.atomic; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -190,16 +192,8 @@ public boolean attemptMark(V expectedReference, boolean newMark) { } // VarHandle mechanics - private static final VarHandle PAIR; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - PAIR = l.findVarHandle(AtomicMarkableReference.class, "pair", - Pair.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle PAIR = MhUtil.findVarHandle( + MethodHandles.lookup(), "pair", Pair.class); private boolean casPair(Pair cmp, Pair val) { return PAIR.compareAndSet(this, cmp, val); diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java index da445da61badc..e512c91f2dfac 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReference.java @@ -35,6 +35,8 @@ package java.util.concurrent.atomic; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.function.BinaryOperator; @@ -50,15 +52,8 @@ */ public class AtomicReference implements java.io.Serializable { private static final long serialVersionUID = -1848883965231344442L; - private static final VarHandle VALUE; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - VALUE = l.findVarHandle(AtomicReference.class, "value", Object.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle VALUE = MhUtil.findVarHandle( + MethodHandles.lookup(), "value", Object.class); @SuppressWarnings("serial") // Conditionally serializable private volatile V value; diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java index b4152c50855c1..bac164b874a1d 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/AtomicStampedReference.java @@ -35,6 +35,8 @@ package java.util.concurrent.atomic; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; @@ -190,16 +192,8 @@ public boolean attemptStamp(V expectedReference, int newStamp) { } // VarHandle mechanics - private static final VarHandle PAIR; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - PAIR = l.findVarHandle(AtomicStampedReference.class, "pair", - Pair.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle PAIR = MhUtil.findVarHandle( + MethodHandles.lookup(), "pair", Pair.class); private boolean casPair(Pair cmp, Pair val) { return PAIR.compareAndSet(this, cmp, val); diff --git a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java index 61a9f4d79e9a3..04ae2b4515825 100644 --- a/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java +++ b/src/java.base/share/classes/java/util/concurrent/atomic/Striped64.java @@ -35,6 +35,8 @@ package java.util.concurrent.atomic; +import jdk.internal.invoke.MhUtil; + import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import java.util.Arrays; @@ -138,15 +140,8 @@ final long getAndSet(long val) { } // VarHandle mechanics - private static final VarHandle VALUE; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - VALUE = l.findVarHandle(Cell.class, "value", long.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + private static final VarHandle VALUE = MhUtil.findVarHandle( + MethodHandles.lookup(), "value", long.class); } /** Number of CPUS, to place bound on table size */ @@ -381,14 +376,12 @@ else if (casBase(v = base, apply(fn, v, x))) private static final VarHandle CELLSBUSY; private static final VarHandle THREAD_PROBE; static { - try { - MethodHandles.Lookup l1 = MethodHandles.lookup(); - BASE = l1.findVarHandle(Striped64.class, - "base", long.class); - CELLSBUSY = l1.findVarHandle(Striped64.class, - "cellsBusy", int.class); + MethodHandles.Lookup l1 = MethodHandles.lookup(); + + BASE = MhUtil.findVarHandle(l1, "base", long.class); + CELLSBUSY = MhUtil.findVarHandle(l1, "cellsBusy", int.class); @SuppressWarnings("removal") - MethodHandles.Lookup l2 = java.security.AccessController.doPrivileged( + MethodHandles.Lookup l2 = java.security.AccessController.doPrivileged( new java.security.PrivilegedAction<>() { public MethodHandles.Lookup run() { try { @@ -397,11 +390,7 @@ public MethodHandles.Lookup run() { throw new ExceptionInInitializerError(e); } }}); - THREAD_PROBE = l2.findVarHandle(Thread.class, - "threadLocalRandomProbe", int.class); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } + THREAD_PROBE = MhUtil.findVarHandle(l2, "threadLocalRandomProbe", int.class); } } diff --git a/src/java.base/share/classes/java/util/jar/JarFile.java b/src/java.base/share/classes/java/util/jar/JarFile.java index 77dfed3b84f2e..3dc3a49dc778e 100644 --- a/src/java.base/share/classes/java/util/jar/JarFile.java +++ b/src/java.base/share/classes/java/util/jar/JarFile.java @@ -90,7 +90,7 @@ *

    If the {@code verify} flag is on when opening a signed jar file, the content * of the jar entry is verified against the signature embedded inside the manifest * that is associated with its {@link JarEntry#getRealName() path name}. For a - * multi-release jar file, the content of a versioned entry is verfieid against + * multi-release jar file, the content of a versioned entry is verified against * its own signature and {@link JarEntry#getCodeSigners()} returns its own signers. * * Please note that the verification process does not include validating the diff --git a/src/java.base/share/classes/java/util/stream/ForEachOps.java b/src/java.base/share/classes/java/util/stream/ForEachOps.java index 0c6b8aa665a78..1ba5970915226 100644 --- a/src/java.base/share/classes/java/util/stream/ForEachOps.java +++ b/src/java.base/share/classes/java/util/stream/ForEachOps.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2012, 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 @@ -24,6 +24,8 @@ */ package java.util.stream; +import jdk.internal.invoke.MhUtil; + import java.util.Objects; import java.util.Spliterator; import java.util.concurrent.CountedCompleter; @@ -370,15 +372,8 @@ static final class ForEachOrderedTask extends CountedCompleter { private Node node; private ForEachOrderedTask next; - private static final VarHandle NEXT; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - NEXT = l.findVarHandle(ForEachOrderedTask.class, "next", ForEachOrderedTask.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle NEXT = MhUtil.findVarHandle( + MethodHandles.lookup(), "next", ForEachOrderedTask.class); protected ForEachOrderedTask(PipelineHelper helper, Spliterator spliterator, diff --git a/src/java.base/share/classes/java/util/stream/GathererOp.java b/src/java.base/share/classes/java/util/stream/GathererOp.java index 8a7073f63ef72..37f01901201eb 100644 --- a/src/java.base/share/classes/java/util/stream/GathererOp.java +++ b/src/java.base/share/classes/java/util/stream/GathererOp.java @@ -24,6 +24,7 @@ */ package java.util.stream; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.annotation.ForceInline; import java.lang.invoke.MethodHandles; @@ -453,16 +454,8 @@ final class Hybrid extends CountedCompleter { private Spliterator spliterator; private Hybrid next; - private static final VarHandle NEXT; - - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - NEXT = l.findVarHandle(Hybrid.class, "next", Hybrid.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle NEXT = MhUtil.findVarHandle( + MethodHandles.lookup(), "next", Hybrid.class); protected Hybrid(Spliterator spliterator) { super(null); diff --git a/src/java.base/share/classes/java/util/zip/ZipCoder.java b/src/java.base/share/classes/java/util/zip/ZipCoder.java index 6692703c1b3f0..8d4a05389eede 100644 --- a/src/java.base/share/classes/java/util/zip/ZipCoder.java +++ b/src/java.base/share/classes/java/util/zip/ZipCoder.java @@ -56,28 +56,27 @@ public static ZipCoder get(Charset charset) { } /** - * This enum represents the three possible return values for + * Constants representing the three possible return values for * {@link #compare(String, byte[], int, int, boolean)} when * this method compares a lookup name to a string encoded in the * CEN byte array. */ - enum Comparison { - /** + static final byte + /* * The lookup string is exactly equal * to the encoded string. - */ - EXACT_MATCH, - /** + */ + EXACT_MATCH = 0, + /* * The lookup string and the encoded string differs only * by the encoded string having a trailing '/' character. */ - DIRECTORY_MATCH, - /** + DIRECTORY_MATCH = 1, + /* * The lookup string and the encoded string do not match. * (They are neither an exact match or a directory match.) */ - NO_MATCH - } + NO_MATCH = 2; String toString(byte[] ba, int off, int length) { try { @@ -197,13 +196,13 @@ private CharsetEncoder encoder() { * The return values of this method are as follows: * * If the lookup name is exactly equal to the encoded string, return - * {@link Comparison#EXACT_MATCH}. + * {@link EXACT_MATCH}. * * If the parameter {@code matchDirectory} is {@code true} and the * two strings differ only by the encoded string having an extra - * trailing '/' character, then return {@link Comparison#DIRECTORY_MATCH}. + * trailing '/' character, then return {@link DIRECTORY_MATCH}. * - * Otherwise, return {@link Comparison#NO_MATCH} + * Otherwise, return {@link NO_MATCH} * * While a general implementation will need to decode bytes into a * String for comparison, this can be avoided if the String coder @@ -217,18 +216,18 @@ private CharsetEncoder encoder() { * a directory match will also be tested * */ - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { String decoded = toString(b, off, len); if (decoded.startsWith(str)) { if (decoded.length() == str.length()) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && decoded.length() == str.length() + 1 && decoded.endsWith("/") ) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } } - return Comparison.NO_MATCH; + return NO_MATCH; } static final class UTF8ZipCoder extends ZipCoder { @@ -278,19 +277,19 @@ private boolean hasTrailingSlash(byte[] a, int end) { } @Override - Comparison compare(String str, byte[] b, int off, int len, boolean matchDirectory) { + byte compare(String str, byte[] b, int off, int len, boolean matchDirectory) { try { byte[] encoded = JLA.getBytesNoRepl(str, UTF_8.INSTANCE); int mismatch = Arrays.mismatch(encoded, 0, encoded.length, b, off, off+len); if (mismatch == -1) { - return Comparison.EXACT_MATCH; + return EXACT_MATCH; } else if (matchDirectory && len == mismatch + 1 && hasTrailingSlash(b, off + len)) { - return Comparison.DIRECTORY_MATCH; + return DIRECTORY_MATCH; } else { - return Comparison.NO_MATCH; + return NO_MATCH; } } catch (CharacterCodingException e) { - return Comparison.NO_MATCH; + return NO_MATCH; } } } diff --git a/src/java.base/share/classes/java/util/zip/ZipEntry.java b/src/java.base/share/classes/java/util/zip/ZipEntry.java index 8c8bfeb322960..243779a7c4913 100644 --- a/src/java.base/share/classes/java/util/zip/ZipEntry.java +++ b/src/java.base/share/classes/java/util/zip/ZipEntry.java @@ -78,7 +78,7 @@ public class ZipEntry implements ZipConstants, Cloneable { /** * Approximately 128 years, in milliseconds (ignoring leap years etc). * - * This establish an approximate high-bound value for DOS times in + * This establishes an approximate high-bound value for DOS times in * milliseconds since epoch, used to enable an efficient but * sufficient bounds check to avoid generating extended last modified * time entries. diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index 333e3d0184976..d54e6c1e4fcb9 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -1869,15 +1869,15 @@ private EntryPos getEntryPos(String name, boolean addSlash) { // Compare the lookup name with the name encoded in the CEN switch (zc.compare(name, cen, noff, nlen, addSlash)) { - case EXACT_MATCH: + case ZipCoder.EXACT_MATCH: // We found an exact match for "name" return new EntryPos(name, pos); - case DIRECTORY_MATCH: + case ZipCoder.DIRECTORY_MATCH: // We found the directory "name/" // Track its position, then continue the search for "name" dirPos = pos; break; - case NO_MATCH: + case ZipCoder.NO_MATCH: // Hash collision, continue searching } } diff --git a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java index f68c27b265ee1..f9712731a0894 100644 --- a/src/java.base/share/classes/java/util/zip/ZipOutputStream.java +++ b/src/java.base/share/classes/java/util/zip/ZipOutputStream.java @@ -378,6 +378,10 @@ public synchronized void write(byte[] b, int off, int len) * Finishes writing the contents of the ZIP output stream without closing * the underlying stream. Use this method when applying multiple filters * in succession to the same output stream. + *

    + * A ZipException will be thrown if the combined length, after encoding, + * of the entry name, the extra field data, the entry comment and + * {@linkplain #CENHDR CEN Header size}, exceeds 65,535 bytes. * @throws ZipException if a ZIP file error has occurred * @throws IOException if an I/O exception has occurred */ @@ -398,7 +402,9 @@ public void finish() throws IOException { } /** - * Closes the ZIP output stream as well as the stream being filtered. + * Closes the underlying stream and the stream being filtered after + * the contents of the ZIP output stream are fully written. + * * @throws ZipException if a ZIP file error has occurred * @throws IOException if an I/O error has occurred */ @@ -589,7 +595,8 @@ private void writeCEN(XEntry xentry) throws IOException { writeInt(csize); // compressed size writeInt(size); // uncompressed size byte[] nameBytes = zc.getBytes(e.name); - writeShort(nameBytes.length); + int nlen = nameBytes.length; + writeShort(nlen); int elen = getExtraLen(e.extra); if (hasZip64) { @@ -626,20 +633,19 @@ private void writeCEN(XEntry xentry) throws IOException { } } writeShort(elen); - byte[] commentBytes; + byte[] commentBytes = null; + int clen = 0; if (e.comment != null) { commentBytes = zc.getBytes(e.comment); - writeShort(Math.min(commentBytes.length, 0xffff)); - } else { - commentBytes = null; - writeShort(0); + clen = Math.min(commentBytes.length, 0xffff); } + writeShort(clen); // file comment length writeShort(0); // starting disk number writeShort(0); // internal file attributes (unused) // extra file attributes, used for storing posix permissions etc. writeInt(e.externalFileAttributes > 0 ? e.externalFileAttributes << 16 : 0); writeInt(offset); // relative offset of local header - writeBytes(nameBytes, 0, nameBytes.length); + writeBytes(nameBytes, 0, nlen); // take care of EXTID_ZIP64 and EXTID_EXTT if (hasZip64) { @@ -679,9 +685,17 @@ private void writeCEN(XEntry xentry) throws IOException { } } } + + // CEN header size + name length + comment length + extra length + // should not exceed 65,535 bytes per the PKWare APP.NOTE + // 4.4.10, 4.4.11, & 4.4.12. + long headerSize = (long)CENHDR + nlen + clen + elen; + if (headerSize > 0xFFFF ) { + throw new ZipException("invalid CEN header (bad header size)"); + } writeExtra(e.extra); if (commentBytes != null) { - writeBytes(commentBytes, 0, Math.min(commentBytes.length, 0xffff)); + writeBytes(commentBytes, 0, clen); } } diff --git a/src/java.base/share/classes/javax/crypto/CryptoPermission.java b/src/java.base/share/classes/javax/crypto/CryptoPermission.java index f13eec7a1d92a..46b5b5fdef6b6 100644 --- a/src/java.base/share/classes/javax/crypto/CryptoPermission.java +++ b/src/java.base/share/classes/javax/crypto/CryptoPermission.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -39,7 +39,7 @@ * The {@code CryptoPermission} class extends the * {@code java.security.Permission} class. A * {@code CryptoPermission} object is used to represent - * the ability of an application/applet to use certain + * the ability of an application to use certain * algorithms with certain key sizes and other * restrictions in certain environments. * diff --git a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java index c08187d88a646..d360b3577a01c 100644 --- a/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java +++ b/src/java.base/share/classes/javax/crypto/ExemptionMechanism.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -43,7 +43,7 @@ * of which are key recovery, key weakening, and * key escrow. * - *

    Applications or applets that use an exemption mechanism may be granted + *

    Applications that use an exemption mechanism may be granted * stronger encryption capabilities than those which don't. * * @since 1.4 diff --git a/src/java.base/share/classes/javax/crypto/JceSecurityManager.java b/src/java.base/share/classes/javax/crypto/JceSecurityManager.java index e9c408a2a56c0..b178c8bfb0253 100644 --- a/src/java.base/share/classes/javax/crypto/JceSecurityManager.java +++ b/src/java.base/share/classes/javax/crypto/JceSecurityManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1999, 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 @@ -36,9 +36,9 @@ * The JCE security manager. * *

    The JCE security manager is responsible for determining the maximum - * allowable cryptographic strength for a given applet/application, for a given + * allowable cryptographic strength for a given application, for a given * algorithm, by consulting the configured jurisdiction policy files and - * the cryptographic permissions bundled with the applet/application. + * the cryptographic permissions bundled with the application. * * @author Jan Luehe * @@ -85,7 +85,7 @@ private JceSecurityManager() { /** * Returns the maximum allowable crypto strength for the given - * applet/application, for the given algorithm. + * application, for the given algorithm. */ CryptoPermission getCryptoPermission(String theAlg) { diff --git a/src/java.base/share/classes/javax/net/SocketFactory.java b/src/java.base/share/classes/javax/net/SocketFactory.java index dd351e9275881..9ef82caf3f9f0 100644 --- a/src/java.base/share/classes/javax/net/SocketFactory.java +++ b/src/java.base/share/classes/javax/net/SocketFactory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 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 @@ -60,7 +60,7 @@ * *

    Factory classes are specified by environment-specific configuration * mechanisms. For example, the getDefault method could return - * a factory that was appropriate for a particular user or applet, and a + * a factory that was appropriate for a particular application, and a * framework could use a factory customized to its own purposes. * * @since 1.4 diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java index 48c0cb7685702..edcd6a7abff25 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractInstruction.java @@ -24,11 +24,11 @@ */ package jdk.internal.classfile.impl; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ConstantDesc; import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.lang.classfile.ClassFile; import java.lang.classfile.Instruction; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.instruction.SwitchCase; @@ -421,7 +421,7 @@ public MemberRefEntry method() { @Override public boolean isInterface() { - return method().tag() == ClassFile.TAG_INTERFACEMETHODREF; + return method().tag() == PoolEntry.TAG_INTERFACE_METHODREF; } @Override diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java index 7ef005eaf6a98..1d8d298857a7b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AbstractPoolEntry.java @@ -30,7 +30,6 @@ import java.nio.charset.StandardCharsets; import java.util.Arrays; -import java.lang.classfile.ClassFile; import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.constantpool.ConstantDynamicEntry; import java.lang.classfile.constantpool.ConstantPool; @@ -84,24 +83,32 @@ public static int hashString(int stringHash) { return stringHash | NON_ZERO; } - public static Utf8Entry rawUtf8EntryFromStandardAttributeName(String name) { - //assuming standard attribute names are all US_ASCII - var raw = name.getBytes(StandardCharsets.US_ASCII); - return new Utf8EntryImpl(null, 0, raw, 0, raw.length); + static int hashClassFromUtf8(boolean isArray, Utf8EntryImpl content) { + int hash = content.contentHash(); + return hashClassFromDescriptor(isArray ? hash : Util.descriptorStringHash(content.length(), hash)); + } + + static int hashClassFromDescriptor(int descriptorHash) { + return hash1(PoolEntry.TAG_CLASS, descriptorHash); + } + + static boolean isArrayDescriptor(Utf8EntryImpl cs) { + // Do not throw out-of-bounds for empty strings + return !cs.isEmpty() && cs.charAt(0) == '['; } @SuppressWarnings("unchecked") public static T maybeClone(ConstantPoolBuilder cp, T entry) { + if (cp.canWriteDirect(entry.constantPool())) + return entry; return (T)((AbstractPoolEntry)entry).clone(cp); } final ConstantPool constantPool; - public final byte tag; private final int index; private final int hash; - private AbstractPoolEntry(ConstantPool constantPool, int tag, int index, int hash) { - this.tag = (byte) tag; + private AbstractPoolEntry(ConstantPool constantPool, int index, int hash) { this.index = index; this.hash = hash; this.constantPool = constantPool; @@ -116,12 +123,10 @@ public int hashCode() { return hash; } - public byte tag() { - return tag; - } + public abstract byte tag(); public int width() { - return (tag == ClassFile.TAG_LONG || tag == ClassFile.TAG_DOUBLE) ? 2 : 1; + return 1; } abstract void writeTo(BufWriterImpl buf); @@ -148,7 +153,7 @@ enum State { RAW, BYTE, CHAR, STRING } private final int offset; private final int rawLen; // Set in any state other than RAW - private @Stable int hash; + private @Stable int contentHash; private @Stable int charLen; // Set in CHAR state private @Stable char[] chars; @@ -159,7 +164,7 @@ enum State { RAW, BYTE, CHAR, STRING } Utf8EntryImpl(ConstantPool cpm, int index, byte[] rawBytes, int offset, int rawLen) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + super(cpm, index, 0); this.rawBytes = rawBytes; this.offset = offset; this.rawLen = rawLen; @@ -167,33 +172,38 @@ enum State { RAW, BYTE, CHAR, STRING } } Utf8EntryImpl(ConstantPool cpm, int index, String s) { - this(cpm, index, s, hashString(s.hashCode())); + this(cpm, index, s, s.hashCode()); } - Utf8EntryImpl(ConstantPool cpm, int index, String s, int hash) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + Utf8EntryImpl(ConstantPool cpm, int index, String s, int contentHash) { + super(cpm, index, 0); this.rawBytes = null; this.offset = 0; this.rawLen = 0; this.state = State.STRING; this.stringValue = s; this.charLen = s.length(); - this.hash = hash; + this.contentHash = contentHash; } Utf8EntryImpl(ConstantPool cpm, int index, Utf8EntryImpl u) { - super(cpm, ClassFile.TAG_UTF8, index, 0); + super(cpm, index, 0); this.rawBytes = u.rawBytes; this.offset = u.offset; this.rawLen = u.rawLen; this.state = u.state; - this.hash = u.hash; + this.contentHash = u.contentHash; this.charLen = u.charLen; this.chars = u.chars; this.stringValue = u.stringValue; this.typeSym = u.typeSym; } + @Override + public byte tag() { + return TAG_UTF8; + } + /** * {@jvms 4.4.7} String content is encoded in modified UTF-8. * @@ -233,7 +243,7 @@ private void inflate() { int singleBytes = JLA.countPositives(rawBytes, offset, rawLen); int hash = ArraysSupport.hashCodeOfUnsigned(rawBytes, offset, singleBytes, 0); if (singleBytes == rawLen) { - this.hash = hashString(hash); + this.contentHash = hash; charLen = rawLen; state = State.BYTE; } @@ -291,7 +301,7 @@ private void inflate() { throw malformedInput(px); } } - this.hash = hashString(hash); + this.contentHash = hash; charLen = chararr_count; this.chars = chararr; state = State.CHAR; @@ -304,8 +314,6 @@ private ConstantPoolException malformedInput(int px) { @Override public Utf8EntryImpl clone(ConstantPoolBuilder cp) { - if (cp.canWriteDirect(constantPool)) - return this; return (state == State.STRING && rawBytes == null) ? (Utf8EntryImpl) cp.utf8Entry(stringValue) : ((SplitConstantPool) cp).maybeCloneUtf8Entry(this); @@ -313,9 +321,13 @@ public Utf8EntryImpl clone(ConstantPoolBuilder cp) { @Override public int hashCode() { + return hashString(contentHash()); + } + + int contentHash() { if (state == State.RAW) inflate(); - return hash; + return contentHash; } @Override @@ -386,6 +398,38 @@ else if ((state == State.STRING && u.state == State.STRING)) return stringValue().equals(u.stringValue()); } + /** + * Returns if this utf8 entry's content equals a substring + * of {@code s} obtained as {@code s.substring(start, end - start)}. + * This check avoids a substring allocation. + */ + public boolean equalsRegion(String s, int start, int end) { + // start and end values trusted + if (state == State.RAW) + inflate(); + int len = charLen; + if (len != end - start) + return false; + + var sv = stringValue; + if (sv != null) { + return sv.regionMatches(0, s, start, len); + } + + var chars = this.chars; + if (chars != null) { + for (int i = 0; i < len; i++) + if (chars[i] != s.charAt(start + i)) + return false; + } else { + var bytes = this.rawBytes; + for (int i = 0; i < len; i++) + if (bytes[offset + i] != s.charAt(start + i)) + return false; + } + return true; + } + @Override public boolean equalsString(String s) { if (state == State.RAW) @@ -394,7 +438,7 @@ public boolean equalsString(String s) { case STRING: return stringValue.equals(s); case CHAR: - if (charLen != s.length() || hash != hashString(s.hashCode())) + if (charLen != s.length() || contentHash != s.hashCode()) return false; for (int i=0; i extends Abstr protected final T ref1; public AbstractRefEntry(ConstantPool constantPool, int tag, int index, T ref1) { - super(constantPool, tag, index, hash1(tag, ref1.index())); + super(constantPool, index, hash1(tag, ref1.index())); this.ref1 = ref1; } @@ -458,7 +502,7 @@ public T ref1() { } void writeTo(BufWriterImpl pool) { - pool.writeU1(tag); + pool.writeU1(tag()); pool.writeU2(ref1.index()); } @@ -474,7 +518,7 @@ abstract static sealed class AbstractRefsEntry elements) implements Annotation { public AnnotationImpl { @@ -62,7 +60,7 @@ public record OfStringImpl(Utf8Entry constant) implements AnnotationValue.OfString { @Override public char tag() { - return AEV_STRING; + return TAG_STRING; } @Override @@ -75,7 +73,7 @@ public record OfDoubleImpl(DoubleEntry constant) implements AnnotationValue.OfDouble { @Override public char tag() { - return AEV_DOUBLE; + return TAG_DOUBLE; } @Override @@ -88,7 +86,7 @@ public record OfFloatImpl(FloatEntry constant) implements AnnotationValue.OfFloat { @Override public char tag() { - return AEV_FLOAT; + return TAG_FLOAT; } @Override @@ -101,7 +99,7 @@ public record OfLongImpl(LongEntry constant) implements AnnotationValue.OfLong { @Override public char tag() { - return AEV_LONG; + return TAG_LONG; } @Override @@ -114,7 +112,7 @@ public record OfIntImpl(IntegerEntry constant) implements AnnotationValue.OfInt { @Override public char tag() { - return AEV_INT; + return TAG_INT; } @Override @@ -127,7 +125,7 @@ public record OfShortImpl(IntegerEntry constant) implements AnnotationValue.OfShort { @Override public char tag() { - return AEV_SHORT; + return TAG_SHORT; } @Override @@ -140,7 +138,7 @@ public record OfCharImpl(IntegerEntry constant) implements AnnotationValue.OfChar { @Override public char tag() { - return AEV_CHAR; + return TAG_CHAR; } @Override @@ -153,7 +151,7 @@ public record OfByteImpl(IntegerEntry constant) implements AnnotationValue.OfByte { @Override public char tag() { - return AEV_BYTE; + return TAG_BYTE; } @Override @@ -166,7 +164,7 @@ public record OfBooleanImpl(IntegerEntry constant) implements AnnotationValue.OfBoolean { @Override public char tag() { - return AEV_BOOLEAN; + return TAG_BOOLEAN; } @Override @@ -183,7 +181,7 @@ public record OfArrayImpl(List values) @Override public char tag() { - return AEV_ARRAY; + return TAG_ARRAY; } } @@ -191,7 +189,7 @@ public record OfEnumImpl(Utf8Entry className, Utf8Entry constantName) implements AnnotationValue.OfEnum { @Override public char tag() { - return AEV_ENUM; + return TAG_ENUM; } } @@ -199,7 +197,7 @@ public record OfAnnotationImpl(Annotation annotation) implements AnnotationValue.OfAnnotation { @Override public char tag() { - return AEV_ANNOTATION; + return TAG_ANNOTATION; } } @@ -207,7 +205,7 @@ public record OfClassImpl(Utf8Entry className) implements AnnotationValue.OfClass { @Override public char tag() { - return AEV_CLASS; + return TAG_CLASS; } } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java index 69511131b3700..e33012ef18353 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/AnnotationReader.java @@ -32,7 +32,8 @@ import java.lang.classfile.ClassReader; import java.lang.classfile.constantpool.*; import java.lang.classfile.TypeAnnotation; -import static java.lang.classfile.ClassFile.*; + +import static java.lang.classfile.AnnotationValue.*; import static java.lang.classfile.TypeAnnotation.TargetInfo.*; import java.util.List; @@ -59,20 +60,20 @@ public static AnnotationValue readElementValue(ClassReader classReader, int p) { char tag = (char) classReader.readU1(p); ++p; return switch (tag) { - case AEV_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); - case AEV_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); - case AEV_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); - case AEV_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); - case AEV_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); - case AEV_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), + case TAG_BYTE -> new AnnotationImpl.OfByteImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_CHAR -> new AnnotationImpl.OfCharImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_DOUBLE -> new AnnotationImpl.OfDoubleImpl(classReader.readEntry(p, DoubleEntry.class)); + case TAG_FLOAT -> new AnnotationImpl.OfFloatImpl(classReader.readEntry(p, FloatEntry.class)); + case TAG_INT -> new AnnotationImpl.OfIntImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_LONG -> new AnnotationImpl.OfLongImpl(classReader.readEntry(p, LongEntry.class)); + case TAG_SHORT -> new AnnotationImpl.OfShortImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_BOOLEAN -> new AnnotationImpl.OfBooleanImpl(classReader.readEntry(p, IntegerEntry.class)); + case TAG_STRING -> new AnnotationImpl.OfStringImpl(classReader.readEntry(p, Utf8Entry.class)); + case TAG_ENUM -> new AnnotationImpl.OfEnumImpl(classReader.readEntry(p, Utf8Entry.class), classReader.readEntry(p + 2, Utf8Entry.class)); - case AEV_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); - case AEV_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); - case AEV_ARRAY -> { + case TAG_CLASS -> new AnnotationImpl.OfClassImpl(classReader.readEntry(p, Utf8Entry.class)); + case TAG_ANNOTATION -> new AnnotationImpl.OfAnnotationImpl(readAnnotation(classReader, p)); + case TAG_ARRAY -> { int numValues = classReader.readU2(p); p += 2; var values = new Object[numValues]; @@ -179,49 +180,49 @@ private static Label getLabel(LabelContext lc, int bciOffset, int targetType, in private static TypeAnnotation readTypeAnnotation(ClassReader classReader, int p, LabelContext lc) { int targetType = classReader.readU1(p++); var targetInfo = switch (targetType) { - case TAT_CLASS_TYPE_PARAMETER -> + case TARGET_CLASS_TYPE_PARAMETER -> ofClassTypeParameter(classReader.readU1(p)); - case TAT_METHOD_TYPE_PARAMETER -> + case TARGET_METHOD_TYPE_PARAMETER -> ofMethodTypeParameter(classReader.readU1(p)); - case TAT_CLASS_EXTENDS -> + case TARGET_CLASS_EXTENDS -> ofClassExtends(classReader.readU2(p)); - case TAT_CLASS_TYPE_PARAMETER_BOUND -> + case TARGET_CLASS_TYPE_PARAMETER_BOUND -> ofClassTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); - case TAT_METHOD_TYPE_PARAMETER_BOUND -> + case TARGET_METHOD_TYPE_PARAMETER_BOUND -> ofMethodTypeParameterBound(classReader.readU1(p), classReader.readU1(p + 1)); - case TAT_FIELD -> + case TARGET_FIELD -> ofField(); - case TAT_METHOD_RETURN -> + case TARGET_METHOD_RETURN -> ofMethodReturn(); - case TAT_METHOD_RECEIVER -> + case TARGET_METHOD_RECEIVER -> ofMethodReceiver(); - case TAT_METHOD_FORMAL_PARAMETER -> + case TARGET_METHOD_FORMAL_PARAMETER -> ofMethodFormalParameter(classReader.readU1(p)); - case TAT_THROWS -> + case TARGET_THROWS -> ofThrows(classReader.readU2(p)); - case TAT_LOCAL_VARIABLE -> + case TARGET_LOCAL_VARIABLE -> ofLocalVariable(readLocalVarEntries(classReader, p, lc, targetType)); - case TAT_RESOURCE_VARIABLE -> + case TARGET_RESOURCE_VARIABLE -> ofResourceVariable(readLocalVarEntries(classReader, p, lc, targetType)); - case TAT_EXCEPTION_PARAMETER -> + case TARGET_EXCEPTION_PARAMETER -> ofExceptionParameter(classReader.readU2(p)); - case TAT_INSTANCEOF -> + case TARGET_INSTANCEOF -> ofInstanceofExpr(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_NEW -> + case TARGET_NEW -> ofNewExpr(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_CONSTRUCTOR_REFERENCE -> + case TARGET_CONSTRUCTOR_REFERENCE -> ofConstructorReference(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_METHOD_REFERENCE -> + case TARGET_METHOD_REFERENCE -> ofMethodReference(getLabel(lc, classReader.readU2(p), targetType, p)); - case TAT_CAST -> + case TARGET_CAST -> ofCastExpr(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> + case TARGET_CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT -> ofConstructorInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_METHOD_INVOCATION_TYPE_ARGUMENT -> + case TARGET_METHOD_INVOCATION_TYPE_ARGUMENT -> ofMethodInvocationTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> + case TARGET_CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT -> ofConstructorReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); - case TAT_METHOD_REFERENCE_TYPE_ARGUMENT -> + case TARGET_METHOD_REFERENCE_TYPE_ARGUMENT -> ofMethodReferenceTypeArgument(getLabel(lc, classReader.readU2(p), targetType, p), classReader.readU1(p + 2)); default -> throw new IllegalArgumentException("Unexpected targetType '%d' in TypeAnnotation, pos = %d".formatted(targetType, p - 1)); @@ -362,16 +363,16 @@ public static void writeAnnotationValue(BufWriterImpl buf, AnnotationValue value var tag = value.tag(); buf.writeU1(tag); switch (value.tag()) { - case AEV_BOOLEAN, AEV_BYTE, AEV_CHAR, AEV_DOUBLE, AEV_FLOAT, AEV_INT, AEV_LONG, AEV_SHORT, AEV_STRING -> + case TAG_BOOLEAN, TAG_BYTE, TAG_CHAR, TAG_DOUBLE, TAG_FLOAT, TAG_INT, TAG_LONG, TAG_SHORT, TAG_STRING -> buf.writeIndex(((AnnotationValue.OfConstant) value).constant()); - case AEV_CLASS -> buf.writeIndex(((AnnotationValue.OfClass) value).className()); - case AEV_ENUM -> { + case TAG_CLASS -> buf.writeIndex(((AnnotationValue.OfClass) value).className()); + case TAG_ENUM -> { var enumValue = (AnnotationValue.OfEnum) value; buf.writeIndex(enumValue.className()); buf.writeIndex(enumValue.constantName()); } - case AEV_ANNOTATION -> writeAnnotation(buf, ((AnnotationValue.OfAnnotation) value).annotation()); - case AEV_ARRAY -> { + case TAG_ANNOTATION -> writeAnnotation(buf, ((AnnotationValue.OfAnnotation) value).annotation()); + case TAG_ARRAY -> { var array = ((AnnotationValue.OfArray) value).values(); buf.writeU2(array.size()); for (var e : array) { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java index 15d3c8f5b347c..4cc6c205fe4ff 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BufWriterImpl.java @@ -36,6 +36,7 @@ import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.ForceInline; public final class BufWriterImpl implements BufWriter { private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); @@ -99,6 +100,7 @@ public void writeU1(int x) { elems[offset++] = (byte) x; } + @ForceInline @Override public void writeU2(int x) { reserveSpace(2); @@ -283,14 +285,19 @@ public void copyTo(byte[] array, int bufferOffset) { // writeIndex methods ensure that any CP info written // is relative to the correct constant pool + @ForceInline @Override public void writeIndex(PoolEntry entry) { int idx = AbstractPoolEntry.maybeClone(constantPool, entry).index(); if (idx < 1 || idx > Character.MAX_VALUE) - throw new IllegalArgumentException(idx + " is not a valid index. Entry: " + entry); + throw invalidIndex(idx, entry); writeU2(idx); } + static IllegalArgumentException invalidIndex(int idx, PoolEntry entry) { + return new IllegalArgumentException(idx + " is not a valid index. Entry: " + entry); + } + @Override public void writeIndexOrZero(PoolEntry entry) { if (entry == null || entry.index() == 0) @@ -298,4 +305,14 @@ public void writeIndexOrZero(PoolEntry entry) { else writeIndex(entry); } + + /** + * Join head and tail into an exact-size buffer + */ + static byte[] join(BufWriterImpl head, BufWriterImpl tail) { + byte[] result = new byte[head.size() + tail.size()]; + head.copyTo(result, 0); + tail.copyTo(result, head.size()); + return result; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java index 75991531c319f..a5b4b55b05b27 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/BytecodeHelpers.java @@ -46,7 +46,7 @@ import java.lang.classfile.constantpool.MethodHandleEntry; import java.lang.classfile.constantpool.NameAndTypeEntry; -import static java.lang.classfile.ClassFile.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * Note: This class switches on opcode.bytecode for code size diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java index 6765bdee3bdac..34e6f5f7c1aa7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassHierarchyImpl.java @@ -40,6 +40,7 @@ import static java.lang.constant.ConstantDescs.CD_Object; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.util.Objects.requireNonNull; import static jdk.internal.constant.ConstantUtils.referenceClassDesc; @@ -174,10 +175,10 @@ public ClassHierarchyResolver.ClassHierarchyInfo getClassInfo(ClassDesc classDes switch (tag = in.readUnsignedByte()) { case TAG_UTF8 -> cpStrings[i] = in.readUTF(); case TAG_CLASS -> cpClasses[i] = in.readUnsignedShort(); - case TAG_STRING, TAG_METHODTYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); - case TAG_METHODHANDLE -> in.skipBytes(3); - case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACEMETHODREF, - TAG_NAMEANDTYPE, TAG_CONSTANTDYNAMIC, TAG_INVOKEDYNAMIC -> in.skipBytes(4); + case TAG_STRING, TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> in.skipBytes(2); + case TAG_METHOD_HANDLE -> in.skipBytes(3); + case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, TAG_INTERFACE_METHODREF, + TAG_NAME_AND_TYPE, TAG_DYNAMIC, TAG_INVOKE_DYNAMIC -> in.skipBytes(4); case TAG_LONG, TAG_DOUBLE -> { in.skipBytes(8); i++; diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java index 837cf3366be83..02026b1acf33d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassPrinterImpl.java @@ -58,9 +58,9 @@ import java.lang.classfile.constantpool.*; import java.lang.classfile.instruction.*; -import static java.lang.classfile.ClassFile.*; import java.lang.classfile.CompoundElement; import java.lang.classfile.FieldModel; +import static java.lang.classfile.constantpool.PoolEntry.*; import static jdk.internal.classfile.impl.ClassPrinterImpl.Style.*; public final class ClassPrinterImpl { @@ -536,21 +536,21 @@ private static Stream convertVTIs(CodeAttribute lr, List { switch (s) { - case ITEM_DOUBLE -> { + case DOUBLE -> { ret.accept("double"); ret.accept("double2"); } - case ITEM_FLOAT -> + case FLOAT -> ret.accept("float"); - case ITEM_INTEGER -> + case INTEGER -> ret.accept("int"); - case ITEM_LONG -> { + case LONG -> { ret.accept("long"); ret.accept("long2"); } - case ITEM_NULL -> ret.accept("null"); - case ITEM_TOP -> ret.accept("?"); - case ITEM_UNINITIALIZED_THIS -> ret.accept("THIS"); + case NULL -> ret.accept("null"); + case TOP -> ret.accept("?"); + case UNINITIALIZED_THIS -> ret.accept("THIS"); } } case ObjectVerificationTypeInfo o -> @@ -603,12 +603,12 @@ private static Node[] constantPoolToTree(ConstantPool cp, Verbosity verbosity) { case TAG_STRING -> "String"; case TAG_FIELDREF -> "Fieldref"; case TAG_METHODREF -> "Methodref"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethodref"; - case TAG_NAMEANDTYPE -> "NameAndType"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethodref"; + case TAG_NAME_AND_TYPE -> "NameAndType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; case TAG_MODULE -> "Module"; case TAG_PACKAGE -> "Package"; default -> throw new AssertionError("Unknown CP tag: " + e.tag()); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java index 6a4b0cd486f07..2ef39504e9b74 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassReaderImpl.java @@ -36,23 +36,7 @@ import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; -import static java.lang.classfile.ClassFile.TAG_CLASS; -import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_DOUBLE; -import static java.lang.classfile.ClassFile.TAG_FIELDREF; -import static java.lang.classfile.ClassFile.TAG_FLOAT; -import static java.lang.classfile.ClassFile.TAG_INTEGER; -import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; -import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_LONG; -import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; -import static java.lang.classfile.ClassFile.TAG_METHODREF; -import static java.lang.classfile.ClassFile.TAG_METHODTYPE; -import static java.lang.classfile.ClassFile.TAG_MODULE; -import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; -import static java.lang.classfile.ClassFile.TAG_PACKAGE; -import static java.lang.classfile.ClassFile.TAG_STRING; -import static java.lang.classfile.ClassFile.TAG_UTF8; +import static java.lang.classfile.constantpool.PoolEntry.*; public final class ClassReaderImpl implements ClassReader { @@ -98,15 +82,15 @@ public final class ClassReaderImpl ++p; switch (tag) { // 2 - case TAG_CLASS, TAG_METHODTYPE, TAG_MODULE, TAG_STRING, TAG_PACKAGE -> p += 2; + case TAG_CLASS, TAG_METHOD_TYPE, TAG_MODULE, TAG_STRING, TAG_PACKAGE -> p += 2; // 3 - case TAG_METHODHANDLE -> p += 3; + case TAG_METHOD_HANDLE -> p += 3; // 4 - case TAG_CONSTANTDYNAMIC, TAG_FIELDREF, TAG_FLOAT, TAG_INTEGER, - TAG_INTERFACEMETHODREF, TAG_INVOKEDYNAMIC, TAG_METHODREF, - TAG_NAMEANDTYPE -> p += 4; + case TAG_DYNAMIC, TAG_FIELDREF, TAG_FLOAT, TAG_INTEGER, + TAG_INTERFACE_METHODREF, TAG_INVOKE_DYNAMIC, TAG_METHODREF, + TAG_NAME_AND_TYPE -> p += 4; // 8 case TAG_DOUBLE, TAG_LONG -> { @@ -354,12 +338,12 @@ private static boolean checkTag(int tag, Class cls) { case TAG_STRING -> AbstractPoolEntry.StringEntryImpl.class; case TAG_FIELDREF -> AbstractPoolEntry.FieldRefEntryImpl.class; case TAG_METHODREF -> AbstractPoolEntry.MethodRefEntryImpl.class; - case TAG_INTERFACEMETHODREF -> AbstractPoolEntry.InterfaceMethodRefEntryImpl.class; - case TAG_NAMEANDTYPE -> AbstractPoolEntry.NameAndTypeEntryImpl.class; - case TAG_METHODHANDLE -> AbstractPoolEntry.MethodHandleEntryImpl.class; - case TAG_METHODTYPE -> AbstractPoolEntry.MethodTypeEntryImpl.class; - case TAG_CONSTANTDYNAMIC -> AbstractPoolEntry.ConstantDynamicEntryImpl.class; - case TAG_INVOKEDYNAMIC -> AbstractPoolEntry.InvokeDynamicEntryImpl.class; + case TAG_INTERFACE_METHODREF -> AbstractPoolEntry.InterfaceMethodRefEntryImpl.class; + case TAG_NAME_AND_TYPE -> AbstractPoolEntry.NameAndTypeEntryImpl.class; + case TAG_METHOD_HANDLE -> AbstractPoolEntry.MethodHandleEntryImpl.class; + case TAG_METHOD_TYPE -> AbstractPoolEntry.MethodTypeEntryImpl.class; + case TAG_DYNAMIC -> AbstractPoolEntry.ConstantDynamicEntryImpl.class; + case TAG_INVOKE_DYNAMIC -> AbstractPoolEntry.InvokeDynamicEntryImpl.class; case TAG_MODULE -> AbstractPoolEntry.ModuleEntryImpl.class; case TAG_PACKAGE -> AbstractPoolEntry.PackageEntryImpl.class; default -> null; @@ -402,15 +386,15 @@ public T entryByIndex(int index, Class cls) { readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); case TAG_METHODREF -> new AbstractPoolEntry.MethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_INTERFACEMETHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), + case TAG_INTERFACE_METHODREF -> new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, index, readEntry(q, AbstractPoolEntry.ClassEntryImpl.class), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_NAMEANDTYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), + case TAG_NAME_AND_TYPE -> new AbstractPoolEntry.NameAndTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class), readEntry(q + 2, AbstractPoolEntry.Utf8EntryImpl.class)); - case TAG_METHODHANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), + case TAG_METHOD_HANDLE -> new AbstractPoolEntry.MethodHandleEntryImpl(this, index, readU1(q), readEntry(q + 1, AbstractPoolEntry.AbstractMemberRefEntry.class)); - case TAG_METHODTYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); - case TAG_CONSTANTDYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); - case TAG_INVOKEDYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_METHOD_TYPE -> new AbstractPoolEntry.MethodTypeEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); + case TAG_DYNAMIC -> new AbstractPoolEntry.ConstantDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); + case TAG_INVOKE_DYNAMIC -> new AbstractPoolEntry.InvokeDynamicEntryImpl(this, index, readU2(q), readEntry(q + 2, AbstractPoolEntry.NameAndTypeEntryImpl.class)); case TAG_MODULE -> new AbstractPoolEntry.ModuleEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); case TAG_PACKAGE -> new AbstractPoolEntry.PackageEntryImpl(this, index, readEntry(q, AbstractPoolEntry.Utf8EntryImpl.class)); default -> throw new ConstantPoolException( diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java index e08d2b76479be..48394d3da96c3 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/CodeImpl.java @@ -39,7 +39,7 @@ import java.lang.classfile.constantpool.ClassEntry; import java.lang.classfile.instruction.*; -import static java.lang.classfile.ClassFile.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class CodeImpl extends BoundAttribute.BoundCodeAttribute diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java index 6901ae7e24cf9..5f02ae708ea7b 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectClassBuilder.java @@ -52,6 +52,8 @@ public final class DirectClassBuilder extends AbstractDirectBuilder implements ClassBuilder { + /** The value of default class access flags */ + static final int DEFAULT_CLASS_FLAGS = ClassFile.ACC_PUBLIC; final ClassEntry thisClassEntry; private final List fields = new ArrayList<>(); private final List methods = new ArrayList<>(); @@ -67,7 +69,7 @@ public DirectClassBuilder(SplitConstantPool constantPool, ClassEntry thisClass) { super(constantPool, context); this.thisClassEntry = AbstractPoolEntry.maybeClone(constantPool, thisClass); - this.flags = ClassFile.DEFAULT_CLASS_FLAGS; + this.flags = DEFAULT_CLASS_FLAGS; this.superclassEntry = null; this.interfaceEntries = Collections.emptyList(); this.majorVersion = ClassFile.latestMajorVersion(); @@ -175,14 +177,16 @@ public byte[] build() { // BSM writers until everything else is written. // Do this early because it might trigger CP activity + var constantPool = this.constantPool; ClassEntry superclass = superclassEntry; if (superclass != null) superclass = AbstractPoolEntry.maybeClone(constantPool, superclass); else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisClassEntry.asInternalName())) superclass = constantPool.classEntry(ConstantDescs.CD_Object); - List ies = new ArrayList<>(interfaceEntries.size()); - for (ClassEntry ce : interfaceEntries) - ies.add(AbstractPoolEntry.maybeClone(constantPool, ce)); + int interfaceEntriesSize = interfaceEntries.size(); + List ies = new ArrayList<>(interfaceEntriesSize); + for (int i = 0; i < interfaceEntriesSize; i++) + ies.add(AbstractPoolEntry.maybeClone(constantPool, interfaceEntries.get(i))); // We maintain two writers, and then we join them at the end int size = sizeHint == 0 ? 256 : sizeHint; @@ -197,16 +201,15 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC attributes.writeTo(tail); // Now we have to append the BSM, if there is one - boolean written = constantPool.writeBootstrapMethods(tail); - if (written) { + if (constantPool.writeBootstrapMethods(tail)) { // Update attributes count tail.patchU2(attributesOffset, attributes.size() + 1); } // Now we can make the head - head.writeInt(ClassFile.MAGIC_NUMBER); - head.writeU2(minorVersion); - head.writeU2(majorVersion); + head.writeLong((((long) ClassFile.MAGIC_NUMBER) << 32) + | ((minorVersion & 0xFFFFL) << 16) + | (majorVersion & 0xFFFFL)); constantPool.writeTo(head); head.writeU2(flags); head.writeIndex(thisClassEntry); @@ -214,9 +217,6 @@ else if ((flags & ClassFile.ACC_MODULE) == 0 && !"java/lang/Object".equals(thisC Util.writeListIndices(head, ies); // Join head and tail into an exact-size buffer - byte[] result = new byte[head.size() + tail.size()]; - head.copyTo(result, 0); - tail.copyTo(result, head.size()); - return result; + return BufWriterImpl.join(head, tail); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java index a9be069591162..301b61241f71e 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/DirectCodeBuilder.java @@ -190,6 +190,13 @@ private void writeExceptionHandlers(BufWriterImpl buf) { int pos = buf.size(); int handlersSize = handlers.size(); buf.writeU2(handlersSize); + if (handlersSize > 0) { + writeExceptionHandlers(buf, pos); + } + } + + private void writeExceptionHandlers(BufWriterImpl buf, int pos) { + int handlersSize = handlers.size(); for (AbstractPseudoInstruction.ExceptionCatchImpl h : handlers) { int startPc = labelToBci(h.tryStart()); int endPc = labelToBci(h.tryEnd()); @@ -482,9 +489,11 @@ private void processDeferredLabels() { // Instruction writing public void writeBytecode(Opcode opcode) { - if (opcode.isWide()) - bytecodesBufWriter.writeU1(ClassFile.WIDE); - bytecodesBufWriter.writeU1(opcode.bytecode() & 0xFF); + if (opcode.isWide()) { + bytecodesBufWriter.writeU2(opcode.bytecode()); + } else { + bytecodesBufWriter.writeU1(opcode.bytecode()); + } } public void writeLocalVar(Opcode opcode, int localVar) { 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 860b7e74b4dde..2403ae150e9dd 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 @@ -32,8 +32,6 @@ import jdk.internal.util.Preconditions; import jdk.internal.vm.annotation.Stable; -import static java.lang.classfile.ClassFile.*; - public final class RawBytecodeHelper { public static final BiFunction, IllegalArgumentException> @@ -43,6 +41,210 @@ public IllegalArgumentException apply(String s) { return new IllegalArgumentException(s); } }); + public static final int + ILLEGAL = -1, + NOP = 0, + ACONST_NULL = 1, + ICONST_M1 = 2, + ICONST_0 = 3, + ICONST_1 = 4, + ICONST_2 = 5, + ICONST_3 = 6, + ICONST_4 = 7, + ICONST_5 = 8, + LCONST_0 = 9, + LCONST_1 = 10, + FCONST_0 = 11, + FCONST_1 = 12, + FCONST_2 = 13, + DCONST_0 = 14, + DCONST_1 = 15, + BIPUSH = 16, + SIPUSH = 17, + LDC = 18, + LDC_W = 19, + LDC2_W = 20, + ILOAD = 21, + LLOAD = 22, + FLOAD = 23, + DLOAD = 24, + ALOAD = 25, + ILOAD_0 = 26, + ILOAD_1 = 27, + ILOAD_2 = 28, + ILOAD_3 = 29, + LLOAD_0 = 30, + LLOAD_1 = 31, + LLOAD_2 = 32, + LLOAD_3 = 33, + FLOAD_0 = 34, + FLOAD_1 = 35, + FLOAD_2 = 36, + FLOAD_3 = 37, + DLOAD_0 = 38, + DLOAD_1 = 39, + DLOAD_2 = 40, + DLOAD_3 = 41, + ALOAD_0 = 42, + ALOAD_1 = 43, + ALOAD_2 = 44, + ALOAD_3 = 45, + IALOAD = 46, + LALOAD = 47, + FALOAD = 48, + DALOAD = 49, + AALOAD = 50, + BALOAD = 51, + CALOAD = 52, + SALOAD = 53, + ISTORE = 54, + LSTORE = 55, + FSTORE = 56, + DSTORE = 57, + ASTORE = 58, + ISTORE_0 = 59, + ISTORE_1 = 60, + ISTORE_2 = 61, + ISTORE_3 = 62, + LSTORE_0 = 63, + LSTORE_1 = 64, + LSTORE_2 = 65, + LSTORE_3 = 66, + FSTORE_0 = 67, + FSTORE_1 = 68, + FSTORE_2 = 69, + FSTORE_3 = 70, + DSTORE_0 = 71, + DSTORE_1 = 72, + DSTORE_2 = 73, + DSTORE_3 = 74, + ASTORE_0 = 75, + ASTORE_1 = 76, + ASTORE_2 = 77, + ASTORE_3 = 78, + IASTORE = 79, + LASTORE = 80, + FASTORE = 81, + DASTORE = 82, + AASTORE = 83, + BASTORE = 84, + CASTORE = 85, + SASTORE = 86, + POP = 87, + POP2 = 88, + DUP = 89, + DUP_X1 = 90, + DUP_X2 = 91, + DUP2 = 92, + DUP2_X1 = 93, + DUP2_X2 = 94, + SWAP = 95, + IADD = 96, + LADD = 97, + FADD = 98, + DADD = 99, + ISUB = 100, + LSUB = 101, + FSUB = 102, + DSUB = 103, + IMUL = 104, + LMUL = 105, + FMUL = 106, + DMUL = 107, + IDIV = 108, + LDIV = 109, + FDIV = 110, + DDIV = 111, + IREM = 112, + LREM = 113, + FREM = 114, + DREM = 115, + INEG = 116, + LNEG = 117, + FNEG = 118, + DNEG = 119, + ISHL = 120, + LSHL = 121, + ISHR = 122, + LSHR = 123, + IUSHR = 124, + LUSHR = 125, + IAND = 126, + LAND = 127, + IOR = 128, + LOR = 129, + IXOR = 130, + LXOR = 131, + IINC = 132, + I2L = 133, + I2F = 134, + I2D = 135, + L2I = 136, + L2F = 137, + L2D = 138, + F2I = 139, + F2L = 140, + F2D = 141, + D2I = 142, + D2L = 143, + D2F = 144, + I2B = 145, + I2C = 146, + I2S = 147, + LCMP = 148, + FCMPL = 149, + FCMPG = 150, + DCMPL = 151, + DCMPG = 152, + IFEQ = 153, + IFNE = 154, + IFLT = 155, + IFGE = 156, + IFGT = 157, + IFLE = 158, + IF_ICMPEQ = 159, + IF_ICMPNE = 160, + IF_ICMPLT = 161, + IF_ICMPGE = 162, + IF_ICMPGT = 163, + IF_ICMPLE = 164, + IF_ACMPEQ = 165, + IF_ACMPNE = 166, + GOTO = 167, + JSR = 168, + RET = 169, + TABLESWITCH = 170, + LOOKUPSWITCH = 171, + IRETURN = 172, + LRETURN = 173, + FRETURN = 174, + DRETURN = 175, + ARETURN = 176, + RETURN = 177, + GETSTATIC = 178, + PUTSTATIC = 179, + GETFIELD = 180, + PUTFIELD = 181, + INVOKEVIRTUAL = 182, + INVOKESPECIAL = 183, + INVOKESTATIC = 184, + INVOKEINTERFACE = 185, + INVOKEDYNAMIC = 186, + NEW = 187, + NEWARRAY = 188, + ANEWARRAY = 189, + ARRAYLENGTH = 190, + ATHROW = 191, + CHECKCAST = 192, + INSTANCEOF = 193, + MONITORENTER = 194, + MONITOREXIT = 195, + WIDE = 196, + MULTIANEWARRAY = 197, + IFNULL = 198, + IFNONNULL = 199, + GOTO_W = 200, + JSR_W = 201; public record CodeRange(byte[] array, int length) { public RawBytecodeHelper start() { @@ -50,8 +252,6 @@ public RawBytecodeHelper start() { } } - public static final int ILLEGAL = -1; - /** * The length of opcodes, or -1 for no fixed length. * This is generated as if: diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java index 0b5d64023b962..2193eb761081d 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SplitConstantPool.java @@ -31,28 +31,14 @@ import java.lang.classfile.Attributes; import java.lang.classfile.ClassReader; -import java.lang.classfile.ClassFile; import java.lang.classfile.BootstrapMethodEntry; import java.lang.classfile.attribute.BootstrapMethodsAttribute; import java.lang.classfile.constantpool.*; import java.util.Objects; -import static java.lang.classfile.ClassFile.TAG_CLASS; -import static java.lang.classfile.ClassFile.TAG_CONSTANTDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_DOUBLE; -import static java.lang.classfile.ClassFile.TAG_FIELDREF; -import static java.lang.classfile.ClassFile.TAG_FLOAT; -import static java.lang.classfile.ClassFile.TAG_INTEGER; -import static java.lang.classfile.ClassFile.TAG_INTERFACEMETHODREF; -import static java.lang.classfile.ClassFile.TAG_INVOKEDYNAMIC; -import static java.lang.classfile.ClassFile.TAG_LONG; -import static java.lang.classfile.ClassFile.TAG_METHODHANDLE; -import static java.lang.classfile.ClassFile.TAG_METHODREF; -import static java.lang.classfile.ClassFile.TAG_METHODTYPE; -import static java.lang.classfile.ClassFile.TAG_MODULE; -import static java.lang.classfile.ClassFile.TAG_NAMEANDTYPE; -import static java.lang.classfile.ClassFile.TAG_PACKAGE; -import static java.lang.classfile.ClassFile.TAG_STRING; +import jdk.internal.constant.ConstantUtils; + +import static java.lang.classfile.constantpool.PoolEntry.*; public final class SplitConstantPool implements ConstantPoolBuilder { @@ -369,9 +355,8 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, String target) { for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_UTF8 + if (e.tag() == TAG_UTF8 && e instanceof AbstractPoolEntry.Utf8EntryImpl ce - && ce.hashCode() == hash && target.equals(ce.stringValue())) return ce; } @@ -386,7 +371,7 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry. EntryMap map = map(); for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { PoolEntry e = entryByIndex(map.getIndexByToken(token)); - if (e.tag() == ClassFile.TAG_UTF8 + if (e.tag() == TAG_UTF8 && e instanceof AbstractPoolEntry.Utf8EntryImpl ce && target.equalsUtf8(ce)) return ce; @@ -398,25 +383,111 @@ private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8(int hash, AbstractPoolEntry. return null; } + private AbstractPoolEntry.Utf8EntryImpl tryFindUtf8OfRegion(int hash, String target, int start, int end) { + EntryMap map = map(); + while (true) { + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = entryByIndex(map.getIndexByToken(token)); + if (e.tag() == TAG_UTF8 + && e instanceof AbstractPoolEntry.Utf8EntryImpl ce + && ce.equalsRegion(target, start, end)) + return ce; + } + if (!doneFullScan) { + fullScan(); + continue; + } + return null; + } + } + + private AbstractPoolEntry.ClassEntryImpl tryFindClassOrInterface(int hash, ClassDesc cd) { + while (true) { + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = entryByIndex(map.getIndexByToken(token)); + if (e.tag() == TAG_CLASS + && e instanceof AbstractPoolEntry.ClassEntryImpl ce) { + var esym = ce.sym; + + if (esym != null) { + if (cd.equals(esym)) { + return ce; // definite match + } + continue; // definite mismatch + } + + // no symbol available + var desc = cd.descriptorString(); + if (ce.ref1.equalsRegion(desc, 1, desc.length() - 1)) { + // definite match, propagate symbol + ce.sym = cd; + return ce; + } + // definite mismatch + } + } + if (!doneFullScan) { + fullScan(); + continue; + } + return null; + } + } + + private AbstractPoolEntry.ClassEntryImpl classEntryForClassOrInterface(ClassDesc cd) { + var desc = cd.descriptorString(); + + int hash = AbstractPoolEntry.hashClassFromDescriptor(desc.hashCode()); + var ce = tryFindClassOrInterface(hash, cd); + if (ce != null) + return ce; + + var utfHash = Util.internalNameHash(desc); + var utf = tryFindUtf8OfRegion(AbstractPoolEntry.hashString(utfHash), desc, 1, desc.length() - 1); + if (utf == null) + utf = internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, ConstantUtils.dropFirstAndLastChar(desc), utfHash)); + + return internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, utf, hash, cd)); + } + + private AbstractPoolEntry.ClassEntryImpl tryFindClassEntry(int hash, AbstractPoolEntry.Utf8EntryImpl utf8) { + EntryMap map = map(); + for (int token = map.firstToken(hash); token != -1; token = map.nextToken(hash, token)) { + PoolEntry e = entryByIndex(map.getIndexByToken(token)); + if (e.tag() == TAG_CLASS + && e instanceof AbstractPoolEntry.ClassEntryImpl ce + && ce.ref1.equalsUtf8(utf8)) + return ce; + } + if (!doneFullScan) { + fullScan(); + return tryFindClassEntry(hash, utf8); + } + return null; + } + @Override - public Utf8Entry utf8Entry(ClassDesc desc) { + public AbstractPoolEntry.Utf8EntryImpl utf8Entry(ClassDesc desc) { var utf8 = utf8Entry(desc.descriptorString()); - utf8.typeSym = desc; + if (utf8.typeSym == null) + utf8.typeSym = desc; return utf8; } @Override public Utf8Entry utf8Entry(MethodTypeDesc desc) { var utf8 = utf8Entry(desc.descriptorString()); - utf8.typeSym = desc; + if (utf8.typeSym == null) + utf8.typeSym = desc; return utf8; } @Override public AbstractPoolEntry.Utf8EntryImpl utf8Entry(String s) { - int hash = AbstractPoolEntry.hashString(s.hashCode()); - var ce = tryFindUtf8(hash, s); - return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s, hash)) : ce; + int contentHash = s.hashCode(); + var ce = tryFindUtf8(AbstractPoolEntry.hashString(contentHash), s); + return ce == null ? internalAdd(new AbstractPoolEntry.Utf8EntryImpl(this, size, s, contentHash)) : ce; } AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) { @@ -429,9 +500,37 @@ AbstractPoolEntry.Utf8EntryImpl maybeCloneUtf8Entry(Utf8Entry entry) { @Override public AbstractPoolEntry.ClassEntryImpl classEntry(Utf8Entry nameEntry) { - AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); - var e = (AbstractPoolEntry.ClassEntryImpl) findEntry(TAG_CLASS, ne); - return e == null ? internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, ne)) : e; + var ne = maybeCloneUtf8Entry(nameEntry); + return classEntry(ne, AbstractPoolEntry.isArrayDescriptor(ne)); + } + + AbstractPoolEntry.ClassEntryImpl classEntry(AbstractPoolEntry.Utf8EntryImpl ne, boolean isArray) { + int hash = AbstractPoolEntry.hashClassFromUtf8(isArray, ne); + var e = tryFindClassEntry(hash, ne); + return e == null ? internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, ne, hash, + isArray && ne.typeSym instanceof ClassDesc cd ? cd : null)) : e; + } + + @Override + public ClassEntry classEntry(ClassDesc cd) { + if (cd.isClassOrInterface()) { // implicit null check + return classEntryForClassOrInterface(cd); + } + if (cd.isArray()) { + return classEntry(utf8Entry(cd), true); + } + throw new IllegalArgumentException("Cannot be encoded as ClassEntry: " + cd.displayName()); + } + + AbstractPoolEntry.ClassEntryImpl cloneClassEntry(AbstractPoolEntry.ClassEntryImpl e) { + var ce = tryFindClassEntry(e.hashCode(), e.ref1); + if (ce != null) { + return ce; + } + + var utf8 = maybeCloneUtf8Entry(e.ref1); // call order matters + return internalAdd(new AbstractPoolEntry.ClassEntryImpl(this, size, + utf8, e.hashCode(), e.sym)); } @Override @@ -452,43 +551,31 @@ public ModuleEntry moduleEntry(Utf8Entry nameEntry) { public AbstractPoolEntry.NameAndTypeEntryImpl nameAndTypeEntry(Utf8Entry nameEntry, Utf8Entry typeEntry) { AbstractPoolEntry.Utf8EntryImpl ne = maybeCloneUtf8Entry(nameEntry); AbstractPoolEntry.Utf8EntryImpl te = maybeCloneUtf8Entry(typeEntry); - var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAMEANDTYPE, ne, te); + var e = (AbstractPoolEntry.NameAndTypeEntryImpl) findEntry(TAG_NAME_AND_TYPE, ne, te); return e == null ? internalAdd(new AbstractPoolEntry.NameAndTypeEntryImpl(this, size, ne, te)) : e; } @Override public FieldRefEntry fieldRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { - AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; - AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; - if (!canWriteDirect(oe.constantPool)) - oe = classEntry(owner.name()); - if (!canWriteDirect(ne.constantPool)) - ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner); + var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); var e = (AbstractPoolEntry.FieldRefEntryImpl) findEntry(TAG_FIELDREF, oe, ne); return e == null ? internalAdd(new AbstractPoolEntry.FieldRefEntryImpl(this, size, oe, ne)) : e; } @Override public MethodRefEntry methodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { - AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; - AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; - if (!canWriteDirect(oe.constantPool)) - oe = classEntry(owner.name()); - if (!canWriteDirect(ne.constantPool)) - ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); + var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner); + var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); var e = (AbstractPoolEntry.MethodRefEntryImpl) findEntry(TAG_METHODREF, oe, ne); return e == null ? internalAdd(new AbstractPoolEntry.MethodRefEntryImpl(this, size, oe, ne)) : e; } @Override public InterfaceMethodRefEntry interfaceMethodRefEntry(ClassEntry owner, NameAndTypeEntry nameAndType) { - AbstractPoolEntry.ClassEntryImpl oe = (AbstractPoolEntry.ClassEntryImpl) owner; - AbstractPoolEntry.NameAndTypeEntryImpl ne = (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType; - if (!canWriteDirect(oe.constantPool)) - oe = classEntry(owner.name()); - if (!canWriteDirect(ne.constantPool)) - ne = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); - var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACEMETHODREF, oe, ne); + var oe = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.ClassEntryImpl) owner); + var ne = AbstractPoolEntry.maybeClone(this, (AbstractPoolEntry.NameAndTypeEntryImpl) nameAndType); + var e = (AbstractPoolEntry.InterfaceMethodRefEntryImpl) findEntry(TAG_INTERFACE_METHODREF, oe, ne); return e == null ? internalAdd(new AbstractPoolEntry.InterfaceMethodRefEntryImpl(this, size, oe, ne)) : e; } @@ -500,26 +587,18 @@ public MethodTypeEntry methodTypeEntry(MethodTypeDesc descriptor) { @Override public MethodTypeEntry methodTypeEntry(Utf8Entry descriptor) { AbstractPoolEntry.Utf8EntryImpl de = maybeCloneUtf8Entry(descriptor); - var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHODTYPE, de); + var e = (AbstractPoolEntry.MethodTypeEntryImpl) findEntry(TAG_METHOD_TYPE, de); return e == null ? internalAdd(new AbstractPoolEntry.MethodTypeEntryImpl(this, size, de)) : e; } @Override public MethodHandleEntry methodHandleEntry(int refKind, MemberRefEntry reference) { - if (!canWriteDirect(reference.constantPool())) { - reference = switch (reference.tag()) { - case TAG_FIELDREF -> fieldRefEntry(reference.owner(), reference.nameAndType()); - case TAG_METHODREF -> methodRefEntry(reference.owner(), reference.nameAndType()); - case TAG_INTERFACEMETHODREF -> interfaceMethodRefEntry(reference.owner(), reference.nameAndType()); - default -> throw new IllegalArgumentException(String.format("Bad tag %d", reference.tag())); - }; - } - - int hash = AbstractPoolEntry.hash2(TAG_METHODHANDLE, refKind, reference.index()); + reference = AbstractPoolEntry.maybeClone(this, reference); + int hash = AbstractPoolEntry.hash2(TAG_METHOD_HANDLE, refKind, reference.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_METHODHANDLE + if (e.tag() == TAG_METHOD_HANDLE && e instanceof AbstractPoolEntry.MethodHandleEntryImpl ce && ce.kind() == refKind && ce.reference() == reference) return ce; @@ -538,14 +617,13 @@ public InvokeDynamicEntry invokeDynamicEntry(BootstrapMethodEntry bootstrapMetho if (!canWriteDirect(bootstrapMethodEntry.constantPool())) bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), bootstrapMethodEntry.arguments()); - if (!canWriteDirect(nameAndType.constantPool())) - nameAndType = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); - int hash = AbstractPoolEntry.hash2(TAG_INVOKEDYNAMIC, + nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType); + int hash = AbstractPoolEntry.hash2(TAG_INVOKE_DYNAMIC, bootstrapMethodEntry.bsmIndex(), nameAndType.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_INVOKEDYNAMIC + if (e.tag() == TAG_INVOKE_DYNAMIC && e instanceof AbstractPoolEntry.InvokeDynamicEntryImpl ce && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) return ce; @@ -569,14 +647,13 @@ public ConstantDynamicEntry constantDynamicEntry(BootstrapMethodEntry bootstrapM if (!canWriteDirect(bootstrapMethodEntry.constantPool())) bootstrapMethodEntry = bsmEntry(bootstrapMethodEntry.bootstrapMethod(), bootstrapMethodEntry.arguments()); - if (!canWriteDirect(nameAndType.constantPool())) - nameAndType = nameAndTypeEntry(nameAndType.name(), nameAndType.type()); - int hash = AbstractPoolEntry.hash2(TAG_CONSTANTDYNAMIC, + nameAndType = AbstractPoolEntry.maybeClone(this, nameAndType); + int hash = AbstractPoolEntry.hash2(TAG_DYNAMIC, bootstrapMethodEntry.bsmIndex(), nameAndType.index()); EntryMap map1 = map(); for (int token = map1.firstToken(hash); token != -1; token = map1.nextToken(hash, token)) { PoolEntry e = entryByIndex(map1.getIndexByToken(token)); - if (e.tag() == TAG_CONSTANTDYNAMIC + if (e.tag() == TAG_DYNAMIC && e instanceof AbstractPoolEntry.ConstantDynamicEntryImpl ce && ce.bootstrap() == bootstrapMethodEntry && ce.nameAndType() == nameAndType) return ce; @@ -628,8 +705,7 @@ public StringEntry stringEntry(Utf8Entry utf8) { @Override public BootstrapMethodEntry bsmEntry(MethodHandleEntry methodReference, List arguments) { - if (!canWriteDirect(methodReference.constantPool())) - methodReference = methodHandleEntry(methodReference.kind(), methodReference.reference()); + methodReference = AbstractPoolEntry.maybeClone(this, methodReference); for (LoadableConstantEntry a : arguments) { if (!canWriteDirect(a.constantPool())) { // copy args list diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java index 783ff4bf106c2..49a06b3acc6e7 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackCounter.java @@ -41,6 +41,8 @@ import java.util.stream.Collectors; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; public final class StackCounter { @@ -120,8 +122,8 @@ public StackCounter(LabelContext labelContext, for (var smfi : smta.entries()) { int frameStack = smfi.stack().size(); for (var vti : smfi.stack()) { - if (vti == StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG - || vti == StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_DOUBLE) frameStack++; + if (vti == StackMapFrameInfo.SimpleVerificationTypeInfo.LONG + || vti == StackMapFrameInfo.SimpleVerificationTypeInfo.DOUBLE) frameStack++; } if (maxStack < frameStack) maxStack = frameStack; targets.add(new Target(labelContext.labelToBci(smfi.target()), frameStack)); @@ -376,11 +378,11 @@ public int maxStack() { private void processLdc(int index) { switch (cp.entryByIndex(index).tag()) { - case TAG_UTF8, TAG_STRING, TAG_CLASS, TAG_INTEGER, TAG_FLOAT, TAG_METHODHANDLE, TAG_METHODTYPE -> + case TAG_UTF8, TAG_STRING, TAG_CLASS, TAG_INTEGER, TAG_FLOAT, TAG_METHOD_HANDLE, TAG_METHOD_TYPE -> addStackSlot(+1); case TAG_DOUBLE, TAG_LONG -> addStackSlot(+2); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> addStackSlot(cp.entryByIndex(index, ConstantDynamicEntry.class).typeKind().slotSize()); default -> throw error("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java index bdee788c9da77..884f7b8bbc8fa 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/StackMapDecoder.java @@ -41,6 +41,7 @@ import java.util.Objects; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.attribute.StackMapFrameInfo.VerificationTypeInfo.*; public class StackMapDecoder { @@ -75,7 +76,7 @@ public static List initFrameLocals(ClassEntry thisClass, S if (!isStatic) { vtis = new VerificationTypeInfo[methodType.parameterCount() + 1]; if ("".equals(methodName) && !ConstantDescs.CD_Object.equals(thisClass.asSymbol())) { - vtis[i++] = SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; + vtis[i++] = SimpleVerificationTypeInfo.UNINITIALIZED_THIS; } else { vtis[i++] = new StackMapDecoder.ObjectVerificationTypeInfoImpl(thisClass); } @@ -85,10 +86,10 @@ public static List initFrameLocals(ClassEntry thisClass, S for (int pi = 0; pi < methodType.parameterCount(); pi++) { var arg = methodType.parameterType(pi); vtis[i++] = switch (arg.descriptorString().charAt(0)) { - case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.ITEM_INTEGER; - case 'J' -> SimpleVerificationTypeInfo.ITEM_LONG; - case 'F' -> SimpleVerificationTypeInfo.ITEM_FLOAT; - case 'D' -> SimpleVerificationTypeInfo.ITEM_DOUBLE; + case 'I', 'S', 'C' ,'B', 'Z' -> SimpleVerificationTypeInfo.INTEGER; + case 'J' -> SimpleVerificationTypeInfo.LONG; + case 'F' -> SimpleVerificationTypeInfo.FLOAT; + case 'D' -> SimpleVerificationTypeInfo.DOUBLE; case 'V' -> throw new IllegalArgumentException("Illegal method argument type: " + arg); default -> new StackMapDecoder.ObjectVerificationTypeInfoImpl(TemporaryConstantPool.INSTANCE.classEntry(arg)); }; @@ -169,11 +170,12 @@ private static boolean equals(List l1, List + case ITEM_TOP, ITEM_INTEGER, ITEM_FLOAT, ITEM_DOUBLE, ITEM_LONG, ITEM_NULL, + ITEM_UNINITIALIZED_THIS -> {} - case VT_OBJECT -> + case ITEM_OBJECT -> bw.writeIndex(((ObjectVerificationTypeInfo)vti).className()); - case VT_UNINITIALIZED -> + case ITEM_UNINITIALIZED -> bw.writeU2(bw.labelContext().labelToBci(((UninitializedVerificationTypeInfo)vti).newTarget())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + vti.tag()); } @@ -232,15 +234,15 @@ List entries() { private VerificationTypeInfo readVerificationTypeInfo() { int tag = classReader.readU1(p++); return switch (tag) { - case VT_TOP -> SimpleVerificationTypeInfo.ITEM_TOP; - case VT_INTEGER -> SimpleVerificationTypeInfo.ITEM_INTEGER; - case VT_FLOAT -> SimpleVerificationTypeInfo.ITEM_FLOAT; - case VT_DOUBLE -> SimpleVerificationTypeInfo.ITEM_DOUBLE; - case VT_LONG -> SimpleVerificationTypeInfo.ITEM_LONG; - case VT_NULL -> SimpleVerificationTypeInfo.ITEM_NULL; - case VT_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.ITEM_UNINITIALIZED_THIS; - case VT_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class)); - case VT_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2())); + case ITEM_TOP -> SimpleVerificationTypeInfo.TOP; + case ITEM_INTEGER -> SimpleVerificationTypeInfo.INTEGER; + case ITEM_FLOAT -> SimpleVerificationTypeInfo.FLOAT; + case ITEM_DOUBLE -> SimpleVerificationTypeInfo.DOUBLE; + case ITEM_LONG -> SimpleVerificationTypeInfo.LONG; + case ITEM_NULL -> SimpleVerificationTypeInfo.NULL; + case ITEM_UNINITIALIZED_THIS -> SimpleVerificationTypeInfo.UNINITIALIZED_THIS; + case ITEM_OBJECT -> new ObjectVerificationTypeInfoImpl(classReader.entryByIndex(u2(), ClassEntry.class)); + case ITEM_UNINITIALIZED -> new UninitializedVerificationTypeInfoImpl(ctx.getLabel(u2())); default -> throw new IllegalArgumentException("Invalid verification type tag: " + tag); }; } @@ -249,7 +251,7 @@ public static record ObjectVerificationTypeInfoImpl( ClassEntry className) implements ObjectVerificationTypeInfo { @Override - public int tag() { return VT_OBJECT; } + public int tag() { return ITEM_OBJECT; } @Override public boolean equals(Object o) { @@ -274,7 +276,7 @@ public String toString() { public static record UninitializedVerificationTypeInfoImpl(Label newTarget) implements UninitializedVerificationTypeInfo { @Override - public int tag() { return VT_UNINITIALIZED; } + public int tag() { return ITEM_UNINITIALIZED; } @Override public String toString() { 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 c6564c289d6f5..ae9835206831e 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 @@ -28,7 +28,6 @@ import java.lang.classfile.Attribute; import java.lang.classfile.Attributes; import java.lang.classfile.BufWriter; -import java.lang.classfile.ClassFile; import java.lang.classfile.Label; import java.lang.classfile.attribute.StackMapTableAttribute; import java.lang.classfile.constantpool.ClassEntry; @@ -48,7 +47,9 @@ import jdk.internal.util.Preconditions; import static java.lang.classfile.ClassFile.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.lang.constant.ConstantDescs.*; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * StackMapGenerator is responsible for stack map frames generation. @@ -400,6 +401,8 @@ private static Type cpIndexToType(int index, ConstantPoolBuilder cp) { } private void processMethod() { + var frames = this.frames; + var currentFrame = this.currentFrame; currentFrame.setLocalsFromArg(methodName, methodDesc, isStatic, thisType); currentFrame.stackSize = 0; currentFrame.flags = 0; @@ -415,10 +418,10 @@ private void processMethod() { throw generatorError("Expecting a stack map frame"); } if (thisOffset == bcs.bci()) { + Frame nextFrame = frames.get(stackmapIndex++); if (!ncf) { - currentFrame.checkAssignableTo(frames.get(stackmapIndex)); + currentFrame.checkAssignableTo(nextFrame); } - Frame nextFrame = frames.get(stackmapIndex++); while (!nextFrame.dirty) { //skip unmatched frames if (stackmapIndex == frames.size()) return; //skip the rest of this round nextFrame = frames.get(stackmapIndex++); @@ -429,7 +432,7 @@ private void processMethod() { currentFrame.copyFrom(nextFrame); nextFrame.dirty = false; } else if (thisOffset < bcs.bci()) { - throw new ClassFormatError(String.format("Bad stack map offset %d", thisOffset)); + throw generatorError("Bad stack map offset"); } } else if (ncf) { throw generatorError("Expecting a stack map frame"); @@ -694,11 +697,11 @@ private void processLdc(int index) { currentFrame.pushStack(Type.DOUBLE_TYPE, Type.DOUBLE2_TYPE); case TAG_LONG -> currentFrame.pushStack(Type.LONG_TYPE, Type.LONG2_TYPE); - case TAG_METHODHANDLE -> + case TAG_METHOD_HANDLE -> currentFrame.pushStack(Type.METHOD_HANDLE_TYPE); - case TAG_METHODTYPE -> + case TAG_METHOD_TYPE -> currentFrame.pushStack(Type.METHOD_TYPE); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> currentFrame.pushStack(cp.entryByIndex(index, ConstantDynamicEntry.class).asSymbol().constantType()); default -> throw generatorError("CP entry #%d %s is not loadable constant".formatted(index, cp.entryByIndex(index).tag())); @@ -1043,34 +1046,37 @@ private void setLocalRawInternal(int index, Type type) { void setLocalsFromArg(String name, MethodTypeDesc methodDesc, boolean isStatic, Type thisKlass) { int localsSize = 0; // Pre-emptively create a locals array that encompass all parameter slots - checkLocal(methodDesc.parameterCount() + (isStatic ? -1 : 0)); + checkLocal(Util.parameterSlots(methodDesc) + (isStatic ? -1 : 0)); + Type type; + Type[] locals = this.locals; if (!isStatic) { - localsSize++; if (OBJECT_INITIALIZER_NAME.equals(name) && !CD_Object.equals(thisKlass.sym)) { - setLocal(0, Type.UNITIALIZED_THIS_TYPE); + type = Type.UNITIALIZED_THIS_TYPE; flags |= FLAG_THIS_UNINIT; } else { - setLocalRawInternal(0, thisKlass); + type = thisKlass; } + locals[localsSize++] = type; } for (int i = 0; i < methodDesc.parameterCount(); i++) { var desc = methodDesc.parameterType(i); - if (!desc.isPrimitive()) { - setLocalRawInternal(localsSize++, Type.referenceType(desc)); - } else switch (desc.descriptorString().charAt(0)) { - case 'J' -> { - setLocalRawInternal(localsSize++, Type.LONG_TYPE); - setLocalRawInternal(localsSize++, Type.LONG2_TYPE); - } - case 'D' -> { - setLocalRawInternal(localsSize++, Type.DOUBLE_TYPE); - setLocalRawInternal(localsSize++, Type.DOUBLE2_TYPE); + if (desc == CD_long) { + locals[localsSize ] = Type.LONG_TYPE; + locals[localsSize + 1] = Type.LONG2_TYPE; + localsSize += 2; + } else if (desc == CD_double) { + locals[localsSize ] = Type.DOUBLE_TYPE; + locals[localsSize + 1] = Type.DOUBLE2_TYPE; + localsSize += 2; + } else { + if (desc instanceof ReferenceClassDescImpl) { + type = Type.referenceType(desc); + } else if (desc == CD_float) { + type = Type.FLOAT_TYPE; + } else { + type = Type.INTEGER_TYPE; } - case 'I', 'Z', 'B', 'C', 'S' -> - setLocalRawInternal(localsSize++, Type.INTEGER_TYPE); - case 'F' -> - setLocalRawInternal(localsSize++, Type.FLOAT_TYPE); - default -> throw new AssertionError("Should not reach here"); + locals[localsSize++] = type; } } this.localsSize = localsSize; @@ -1090,11 +1096,15 @@ void copyFrom(Frame src) { } void checkAssignableTo(Frame target) { + int localsSize = this.localsSize; + int stackSize = this.stackSize; if (target.flags == -1) { - target.locals = locals == null ? null : Arrays.copyOf(locals, localsSize); + target.locals = locals == null ? null : locals.clone(); target.localsSize = localsSize; - target.stack = stack == null ? null : Arrays.copyOf(stack, stackSize); - target.stackSize = stackSize; + if (stackSize > 0) { + target.stack = stack.clone(); + target.stackSize = stackSize; + } target.flags = flags; target.dirty = true; } else { diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java index 3377e3ebd1305..b2d5cd9f62c84 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/TargetInfoImpl.java @@ -28,7 +28,7 @@ import java.util.Objects; import java.lang.classfile.Label; import java.lang.classfile.TypeAnnotation.*; -import static java.lang.classfile.ClassFile.*; + import static java.util.Objects.requireNonNull; public final class TargetInfoImpl { @@ -47,7 +47,7 @@ public record TypeParameterTargetImpl(TargetType targetType, int typeParameterIn implements TypeParameterTarget { public TypeParameterTargetImpl(TargetType targetType, int typeParameterIndex) { - this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER, TAT_METHOD_TYPE_PARAMETER); + this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER, TARGET_METHOD_TYPE_PARAMETER); this.typeParameterIndex = typeParameterIndex; } } @@ -63,7 +63,7 @@ public record TypeParameterBoundTargetImpl(TargetType targetType, int typeParame implements TypeParameterBoundTarget { public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterIndex, int boundIndex) { - this.targetType = checkValid(targetType, TAT_CLASS_TYPE_PARAMETER_BOUND, TAT_METHOD_TYPE_PARAMETER_BOUND); + this.targetType = checkValid(targetType, TARGET_CLASS_TYPE_PARAMETER_BOUND, TARGET_METHOD_TYPE_PARAMETER_BOUND); this.typeParameterIndex = typeParameterIndex; this.boundIndex = boundIndex; } @@ -72,7 +72,7 @@ public TypeParameterBoundTargetImpl(TargetType targetType, int typeParameterInde public record EmptyTargetImpl(TargetType targetType) implements EmptyTarget { public EmptyTargetImpl(TargetType targetType) { - this.targetType = checkValid(targetType, TAT_FIELD, TAT_METHOD_RECEIVER); + this.targetType = checkValid(targetType, TARGET_FIELD, TARGET_METHOD_RECEIVER); } } @@ -94,7 +94,7 @@ public record LocalVarTargetImpl(TargetType targetType, List implements LocalVarTarget { public LocalVarTargetImpl(TargetType targetType, List table) { - this.targetType = checkValid(targetType, TAT_LOCAL_VARIABLE, TAT_RESOURCE_VARIABLE); + this.targetType = checkValid(targetType, TARGET_LOCAL_VARIABLE, TARGET_RESOURCE_VARIABLE); this.table = List.copyOf(table); } @Override @@ -122,7 +122,7 @@ public TargetType targetType() { public record OffsetTargetImpl(TargetType targetType, Label target) implements OffsetTarget { public OffsetTargetImpl(TargetType targetType, Label target) { - this.targetType = checkValid(targetType, TAT_INSTANCEOF, TAT_METHOD_REFERENCE); + this.targetType = checkValid(targetType, TARGET_INSTANCEOF, TARGET_METHOD_REFERENCE); this.target = requireNonNull(target); } } @@ -131,7 +131,7 @@ public record TypeArgumentTargetImpl(TargetType targetType, Label target, int ty implements TypeArgumentTarget { public TypeArgumentTargetImpl(TargetType targetType, Label target, int typeArgumentIndex) { - this.targetType = checkValid(targetType, TAT_CAST, TAT_METHOD_REFERENCE_TYPE_ARGUMENT); + this.targetType = checkValid(targetType, TARGET_CAST, TARGET_METHOD_REFERENCE_TYPE_ARGUMENT); this.target = requireNonNull(target); this.typeArgumentIndex = typeArgumentIndex; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java index 7f3dd914e7f8c..e1e3f6fb3d2b4 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/Util.java @@ -50,6 +50,8 @@ import java.lang.constant.ModuleDesc; import java.lang.reflect.AccessFlag; import jdk.internal.access.SharedSecrets; +import jdk.internal.vm.annotation.ForceInline; +import jdk.internal.vm.annotation.Stable; import static java.lang.classfile.ClassFile.ACC_STATIC; import java.lang.classfile.attribute.CodeAttribute; @@ -248,17 +250,21 @@ private static > void writeAttribute(BufWriterImpl writer } } + @ForceInline public static void writeAttributes(BufWriterImpl buf, List> list) { - buf.writeU2(list.size()); - for (var e : list) { - writeAttribute(buf, e); + int size = list.size(); + buf.writeU2(size); + for (int i = 0; i < size; i++) { + writeAttribute(buf, list.get(i)); } } + @ForceInline static void writeList(BufWriterImpl buf, List list) { - buf.writeU2(list.size()); - for (var e : list) { - e.writeTo(buf); + int size = list.size(); + buf.writeU2(size); + for (int i = 0; i < size; i++) { + list.get(i).writeTo(buf); } } @@ -337,4 +343,82 @@ interface Writable { interface WritableLocalVariable { boolean writeLocalTo(BufWriterImpl buf); } + + /** + * Returns the hash code of an internal name given the class or interface L descriptor. + */ + public static int internalNameHash(String desc) { + if (desc.length() > 0xffff) + throw new IllegalArgumentException("String too long: ".concat(Integer.toString(desc.length()))); + return (desc.hashCode() - pow31(desc.length() - 1) * 'L' - ';') * INVERSE_31; + } + + /** + * Returns the hash code of a class or interface L descriptor given the internal name. + */ + public static int descriptorStringHash(int length, int hash) { + if (length > 0xffff) + throw new IllegalArgumentException("String too long: ".concat(Integer.toString(length))); + return 'L' * pow31(length + 1) + hash * 31 + ';'; + } + + // k is at most 65536, length of Utf8 entry + 1 + public static int pow31(int k) { + int r = 1; + // calculate the power contribution from index-th octal digit + // from least to most significant (right to left) + // e.g. decimal 26=octal 32, power(26)=powerOctal(2,0)*powerOctal(3,1) + for (int i = 0; i < SIGNIFICANT_OCTAL_DIGITS; i++) { + r *= powerOctal(k & 7, i); + k >>= 3; + } + return r; + } + + // The inverse of 31 in Z/2^32Z* modulo group, a * INVERSE_31 * 31 = a + static final int INVERSE_31 = 0xbdef7bdf; + + // k is at most 65536 = octal 200000, only consider 6 octal digits + // Note: 31 powers repeat beyond 1 << 27, only 9 octal digits matter + static final int SIGNIFICANT_OCTAL_DIGITS = 6; + + // for base k, storage is k * log_k(N)=k/ln(k) * ln(N) + // k = 2 or 4 is better for space at the cost of more multiplications + /** + * The code below is as if: + * {@snippet lang=java : + * int[] powers = new int[7 * SIGNIFICANT_OCTAL_DIGITS]; + * + * for (int i = 1, k = 31; i <= 7; i++, k *= 31) { + * int t = powers[powersIndex(i, 0)] = k; + * for (int j = 1; j < SIGNIFICANT_OCTAL_DIGITS; j++) { + * t *= t; + * t *= t; + * t *= t; + * powers[powersIndex(i, j)] = t; + * } + * } + * } + * This is converted to explicit initialization to avoid bootstrap overhead. + * Validated in UtilTest. + */ + static final @Stable int[] powers = new int[] { + 0x0000001f, 0x000003c1, 0x0000745f, 0x000e1781, 0x01b4d89f, 0x34e63b41, 0x67e12cdf, + 0x94446f01, 0x50a9de01, 0x84304d01, 0x7dd7bc01, 0x8ca02b01, 0xff899a01, 0x25940901, + 0x4dbf7801, 0xe3bef001, 0xc1fe6801, 0xe87de001, 0x573d5801, 0x0e3cd001, 0x0d7c4801, + 0x54fbc001, 0xb9f78001, 0x2ef34001, 0xb3ef0001, 0x48eac001, 0xede68001, 0xa2e24001, + 0x67de0001, 0xcfbc0001, 0x379a0001, 0x9f780001, 0x07560001, 0x6f340001, 0xd7120001, + 0x3ef00001, 0x7de00001, 0xbcd00001, 0xfbc00001, 0x3ab00001, 0x79a00001, 0xb8900001, + }; + + static int powersIndex(int digit, int index) { + return (digit - 1) + index * 7; + } + + // (31 ^ digit) ^ (8 * index) = 31 ^ (digit * (8 ^ index)) + // digit: 0 - 7 + // index: 0 - SIGNIFICANT_OCTAL_DIGITS - 1 + private static int powerOctal(int digit, int index) { + return digit == 0 ? 1 : powers[powersIndex(digit, index)]; + } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java index de97730aff579..5aed968c6aefc 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerificationBytecodes.java @@ -24,7 +24,7 @@ */ package jdk.internal.classfile.impl.verifier; -import java.lang.classfile.ClassFile; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; @@ -83,7 +83,7 @@ static boolean is_valid(int code) { } static boolean is_store_into_local(int code) { - return (ClassFile.ISTORE <= code && code <= ClassFile.ASTORE_3); + return (ISTORE <= code && code <= ASTORE_3); } static final int _lengths[] = new int[number_of_codes]; @@ -104,244 +104,244 @@ static void def(int code, String name, String format, String wide_format, BasicT } static { - def(ClassFile.NOP, "nop", "b", null, T_VOID, 0); - def(ClassFile.ACONST_NULL, "aconst_null", "b", null, T_OBJECT, 1); - def(ClassFile.ICONST_M1, "iconst_m1", "b", null, T_INT, 1); - def(ClassFile.ICONST_0, "iconst_0", "b", null, T_INT, 1); - def(ClassFile.ICONST_1, "iconst_1", "b", null, T_INT, 1); - def(ClassFile.ICONST_2, "iconst_2", "b", null, T_INT, 1); - def(ClassFile.ICONST_3, "iconst_3", "b", null, T_INT, 1); - def(ClassFile.ICONST_4, "iconst_4", "b", null, T_INT, 1); - def(ClassFile.ICONST_5, "iconst_5", "b", null, T_INT, 1); - def(ClassFile.LCONST_0, "lconst_0", "b", null, T_LONG, 2); - def(ClassFile.LCONST_1, "lconst_1", "b", null, T_LONG, 2); - def(ClassFile.FCONST_0, "fconst_0", "b", null, T_FLOAT, 1); - def(ClassFile.FCONST_1, "fconst_1", "b", null, T_FLOAT, 1); - def(ClassFile.FCONST_2, "fconst_2", "b", null, T_FLOAT, 1); - def(ClassFile.DCONST_0, "dconst_0", "b", null, T_DOUBLE, 2); - def(ClassFile.DCONST_1, "dconst_1", "b", null, T_DOUBLE, 2); - def(ClassFile.BIPUSH, "bipush", "bc", null, T_INT, 1); - def(ClassFile.SIPUSH, "sipush", "bcc", null, T_INT, 1); - def(ClassFile.LDC, "ldc", "bk", null, T_ILLEGAL, 1); - def(ClassFile.LDC_W, "ldc_w", "bkk", null, T_ILLEGAL, 1); - def(ClassFile.LDC2_W, "ldc2_w", "bkk", null, T_ILLEGAL, 2); - def(ClassFile.ILOAD, "iload", "bi", "wbii", T_INT, 1); - def(ClassFile.LLOAD, "lload", "bi", "wbii", T_LONG, 2); - def(ClassFile.FLOAD, "fload", "bi", "wbii", T_FLOAT, 1); - def(ClassFile.DLOAD, "dload", "bi", "wbii", T_DOUBLE, 2); - def(ClassFile.ALOAD, "aload", "bi", "wbii", T_OBJECT, 1); - def(ClassFile.ILOAD_0, "iload_0", "b", null, T_INT, 1); - def(ClassFile.ILOAD_1, "iload_1", "b", null, T_INT, 1); - def(ClassFile.ILOAD_2, "iload_2", "b", null, T_INT, 1); - def(ClassFile.ILOAD_3, "iload_3", "b", null, T_INT, 1); - def(ClassFile.LLOAD_0, "lload_0", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_1, "lload_1", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_2, "lload_2", "b", null, T_LONG, 2); - def(ClassFile.LLOAD_3, "lload_3", "b", null, T_LONG, 2); - def(ClassFile.FLOAD_0, "fload_0", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_1, "fload_1", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_2, "fload_2", "b", null, T_FLOAT, 1); - def(ClassFile.FLOAD_3, "fload_3", "b", null, T_FLOAT, 1); - def(ClassFile.DLOAD_0, "dload_0", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_1, "dload_1", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_2, "dload_2", "b", null, T_DOUBLE, 2); - def(ClassFile.DLOAD_3, "dload_3", "b", null, T_DOUBLE, 2); - def(ClassFile.ALOAD_0, "aload_0", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_1, "aload_1", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_2, "aload_2", "b", null, T_OBJECT, 1); - def(ClassFile.ALOAD_3, "aload_3", "b", null, T_OBJECT, 1); - def(ClassFile.IALOAD, "iaload", "b", null, T_INT, -1); - def(ClassFile.LALOAD, "laload", "b", null, T_LONG, 0); - def(ClassFile.FALOAD, "faload", "b", null, T_FLOAT, -1); - def(ClassFile.DALOAD, "daload", "b", null, T_DOUBLE, 0); - def(ClassFile.AALOAD, "aaload", "b", null, T_OBJECT, -1); - def(ClassFile.BALOAD, "baload", "b", null, T_INT, -1); - def(ClassFile.CALOAD, "caload", "b", null, T_INT, -1); - def(ClassFile.SALOAD, "saload", "b", null, T_INT, -1); - def(ClassFile.ISTORE, "istore", "bi", "wbii", T_VOID, -1); - def(ClassFile.LSTORE, "lstore", "bi", "wbii", T_VOID, -2); - def(ClassFile.FSTORE, "fstore", "bi", "wbii", T_VOID, -1); - def(ClassFile.DSTORE, "dstore", "bi", "wbii", T_VOID, -2); - def(ClassFile.ASTORE, "astore", "bi", "wbii", T_VOID, -1); - def(ClassFile.ISTORE_0, "istore_0", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_1, "istore_1", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_2, "istore_2", "b", null, T_VOID, -1); - def(ClassFile.ISTORE_3, "istore_3", "b", null, T_VOID, -1); - def(ClassFile.LSTORE_0, "lstore_0", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_1, "lstore_1", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_2, "lstore_2", "b", null, T_VOID, -2); - def(ClassFile.LSTORE_3, "lstore_3", "b", null, T_VOID, -2); - def(ClassFile.FSTORE_0, "fstore_0", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_1, "fstore_1", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_2, "fstore_2", "b", null, T_VOID, -1); - def(ClassFile.FSTORE_3, "fstore_3", "b", null, T_VOID, -1); - def(ClassFile.DSTORE_0, "dstore_0", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_1, "dstore_1", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_2, "dstore_2", "b", null, T_VOID, -2); - def(ClassFile.DSTORE_3, "dstore_3", "b", null, T_VOID, -2); - def(ClassFile.ASTORE_0, "astore_0", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_1, "astore_1", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_2, "astore_2", "b", null, T_VOID, -1); - def(ClassFile.ASTORE_3, "astore_3", "b", null, T_VOID, -1); - def(ClassFile.IASTORE, "iastore", "b", null, T_VOID, -3); - def(ClassFile.LASTORE, "lastore", "b", null, T_VOID, -4); - def(ClassFile.FASTORE, "fastore", "b", null, T_VOID, -3); - def(ClassFile.DASTORE, "dastore", "b", null, T_VOID, -4); - def(ClassFile.AASTORE, "aastore", "b", null, T_VOID, -3); - def(ClassFile.BASTORE, "bastore", "b", null, T_VOID, -3); - def(ClassFile.CASTORE, "castore", "b", null, T_VOID, -3); - def(ClassFile.SASTORE, "sastore", "b", null, T_VOID, -3); - def(ClassFile.POP, "pop", "b", null, T_VOID, -1); - def(ClassFile.POP2, "pop2", "b", null, T_VOID, -2); - def(ClassFile.DUP, "dup", "b", null, T_VOID, 1); - def(ClassFile.DUP_X1, "dup_x1", "b", null, T_VOID, 1); - def(ClassFile.DUP_X2, "dup_x2", "b", null, T_VOID, 1); - def(ClassFile.DUP2, "dup2", "b", null, T_VOID, 2); - def(ClassFile.DUP2_X1, "dup2_x1", "b", null, T_VOID, 2); - def(ClassFile.DUP2_X2, "dup2_x2", "b", null, T_VOID, 2); - def(ClassFile.SWAP, "swap", "b", null, T_VOID, 0); - def(ClassFile.IADD, "iadd", "b", null, T_INT, -1); - def(ClassFile.LADD, "ladd", "b", null, T_LONG, -2); - def(ClassFile.FADD, "fadd", "b", null, T_FLOAT, -1); - def(ClassFile.DADD, "dadd", "b", null, T_DOUBLE, -2); - def(ClassFile.ISUB, "isub", "b", null, T_INT, -1); - def(ClassFile.LSUB, "lsub", "b", null, T_LONG, -2); - def(ClassFile.FSUB, "fsub", "b", null, T_FLOAT, -1); - def(ClassFile.DSUB, "dsub", "b", null, T_DOUBLE, -2); - def(ClassFile.IMUL, "imul", "b", null, T_INT, -1); - def(ClassFile.LMUL, "lmul", "b", null, T_LONG, -2); - def(ClassFile.FMUL, "fmul", "b", null, T_FLOAT, -1); - def(ClassFile.DMUL, "dmul", "b", null, T_DOUBLE, -2); - def(ClassFile.IDIV, "idiv", "b", null, T_INT, -1); - def(ClassFile.LDIV, "ldiv", "b", null, T_LONG, -2); - def(ClassFile.FDIV, "fdiv", "b", null, T_FLOAT, -1); - def(ClassFile.DDIV, "ddiv", "b", null, T_DOUBLE, -2); - def(ClassFile.IREM, "irem", "b", null, T_INT, -1); - def(ClassFile.LREM, "lrem", "b", null, T_LONG, -2); - def(ClassFile.FREM, "frem", "b", null, T_FLOAT, -1); - def(ClassFile.DREM, "drem", "b", null, T_DOUBLE, -2); - def(ClassFile.INEG, "ineg", "b", null, T_INT, 0); - def(ClassFile.LNEG, "lneg", "b", null, T_LONG, 0); - def(ClassFile.FNEG, "fneg", "b", null, T_FLOAT, 0); - def(ClassFile.DNEG, "dneg", "b", null, T_DOUBLE, 0); - def(ClassFile.ISHL, "ishl", "b", null, T_INT, -1); - def(ClassFile.LSHL, "lshl", "b", null, T_LONG, -1); - def(ClassFile.ISHR, "ishr", "b", null, T_INT, -1); - def(ClassFile.LSHR, "lshr", "b", null, T_LONG, -1); - def(ClassFile.IUSHR, "iushr", "b", null, T_INT, -1); - def(ClassFile.LUSHR, "lushr", "b", null, T_LONG, -1); - def(ClassFile.IAND, "iand", "b", null, T_INT, -1); - def(ClassFile.LAND, "land", "b", null, T_LONG, -2); - def(ClassFile.IOR, "ior", "b", null, T_INT, -1); - def(ClassFile.LOR, "lor", "b", null, T_LONG, -2); - def(ClassFile.IXOR, "ixor", "b", null, T_INT, -1); - def(ClassFile.LXOR, "lxor", "b", null, T_LONG, -2); - def(ClassFile.IINC, "iinc", "bic", "wbiicc", T_VOID, 0); - def(ClassFile.I2L, "i2l", "b", null, T_LONG, 1); - def(ClassFile.I2F, "i2f", "b", null, T_FLOAT, 0); - def(ClassFile.I2D, "i2d", "b", null, T_DOUBLE, 1); - def(ClassFile.L2I, "l2i", "b", null, T_INT, -1); - def(ClassFile.L2F, "l2f", "b", null, T_FLOAT, -1); - def(ClassFile.L2D, "l2d", "b", null, T_DOUBLE, 0); - def(ClassFile.F2I, "f2i", "b", null, T_INT, 0); - def(ClassFile.F2L, "f2l", "b", null, T_LONG, 1); - def(ClassFile.F2D, "f2d", "b", null, T_DOUBLE, 1); - def(ClassFile.D2I, "d2i", "b", null, T_INT, -1); - def(ClassFile.D2L, "d2l", "b", null, T_LONG, 0); - def(ClassFile.D2F, "d2f", "b", null, T_FLOAT, -1); - def(ClassFile.I2B, "i2b", "b", null, T_BYTE, 0); - def(ClassFile.I2C, "i2c", "b", null, T_CHAR, 0); - def(ClassFile.I2S, "i2s", "b", null, T_SHORT, 0); - def(ClassFile.LCMP, "lcmp", "b", null, T_VOID, -3); - def(ClassFile.FCMPL, "fcmpl", "b", null, T_VOID, -1); - def(ClassFile.FCMPG, "fcmpg", "b", null, T_VOID, -1); - def(ClassFile.DCMPL, "dcmpl", "b", null, T_VOID, -3); - def(ClassFile.DCMPG, "dcmpg", "b", null, T_VOID, -3); - def(ClassFile.IFEQ, "ifeq", "boo", null, T_VOID, -1); - def(ClassFile.IFNE, "ifne", "boo", null, T_VOID, -1); - def(ClassFile.IFLT, "iflt", "boo", null, T_VOID, -1); - def(ClassFile.IFGE, "ifge", "boo", null, T_VOID, -1); - def(ClassFile.IFGT, "ifgt", "boo", null, T_VOID, -1); - def(ClassFile.IFLE, "ifle", "boo", null, T_VOID, -1); - def(ClassFile.IF_ICMPEQ, "if_icmpeq", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPNE, "if_icmpne", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPLT, "if_icmplt", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPGE, "if_icmpge", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPGT, "if_icmpgt", "boo", null, T_VOID, -2); - def(ClassFile.IF_ICMPLE, "if_icmple", "boo", null, T_VOID, -2); - def(ClassFile.IF_ACMPEQ, "if_acmpeq", "boo", null, T_VOID, -2); - def(ClassFile.IF_ACMPNE, "if_acmpne", "boo", null, T_VOID, -2); - def(ClassFile.GOTO, "goto", "boo", null, T_VOID, 0); - def(ClassFile.JSR, "jsr", "boo", null, T_INT, 0); - def(ClassFile.RET, "ret", "bi", "wbii", T_VOID, 0); - def(ClassFile.TABLESWITCH, "tableswitch", "", null, T_VOID, -1); // may have backward branches - def(ClassFile.LOOKUPSWITCH, "lookupswitch", "", null, T_VOID, -1); // rewriting in interpreter - def(ClassFile.IRETURN, "ireturn", "b", null, T_INT, -1); - def(ClassFile.LRETURN, "lreturn", "b", null, T_LONG, -2); - def(ClassFile.FRETURN, "freturn", "b", null, T_FLOAT, -1); - def(ClassFile.DRETURN, "dreturn", "b", null, T_DOUBLE, -2); - def(ClassFile.ARETURN, "areturn", "b", null, T_OBJECT, -1); - def(ClassFile.RETURN, "return", "b", null, T_VOID, 0); - def(ClassFile.GETSTATIC, "getstatic", "bJJ", null, T_ILLEGAL, 1); - def(ClassFile.PUTSTATIC, "putstatic", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.GETFIELD, "getfield", "bJJ", null, T_ILLEGAL, 0); - def(ClassFile.PUTFIELD, "putfield", "bJJ", null, T_ILLEGAL, -2); - def(ClassFile.INVOKEVIRTUAL, "invokevirtual", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.INVOKESPECIAL, "invokespecial", "bJJ", null, T_ILLEGAL, -1); - def(ClassFile.INVOKESTATIC, "invokestatic", "bJJ", null, T_ILLEGAL, 0); - def(ClassFile.INVOKEINTERFACE, "invokeinterface", "bJJ__", null, T_ILLEGAL, -1); - def(ClassFile.INVOKEDYNAMIC, "invokedynamic", "bJJJJ", null, T_ILLEGAL, 0); - def(ClassFile.NEW, "new", "bkk", null, T_OBJECT, 1); - def(ClassFile.NEWARRAY, "newarray", "bc", null, T_OBJECT, 0); - def(ClassFile.ANEWARRAY, "anewarray", "bkk", null, T_OBJECT, 0); - def(ClassFile.ARRAYLENGTH, "arraylength", "b", null, T_VOID, 0); - def(ClassFile.ATHROW, "athrow", "b", null, T_VOID, -1); - def(ClassFile.CHECKCAST, "checkcast", "bkk", null, T_OBJECT, 0); - def(ClassFile.INSTANCEOF, "instanceof", "bkk", null, T_INT, 0); - def(ClassFile.MONITORENTER, "monitorenter", "b", null, T_VOID, -1); - def(ClassFile.MONITOREXIT, "monitorexit", "b", null, T_VOID, -1); - def(ClassFile.WIDE, "wide", "", null, T_VOID, 0); - def(ClassFile.MULTIANEWARRAY, "multianewarray", "bkkc", null, T_OBJECT, 1); - def(ClassFile.IFNULL, "ifnull", "boo", null, T_VOID, -1); - def(ClassFile.IFNONNULL, "ifnonnull", "boo", null, T_VOID, -1); - def(ClassFile.GOTO_W, "goto_w", "boooo", null, T_VOID, 0); - def(ClassFile.JSR_W, "jsr_w", "boooo", null, T_INT, 0); + def(NOP, "nop", "b", null, T_VOID, 0); + def(ACONST_NULL, "aconst_null", "b", null, T_OBJECT, 1); + def(ICONST_M1, "iconst_m1", "b", null, T_INT, 1); + def(ICONST_0, "iconst_0", "b", null, T_INT, 1); + def(ICONST_1, "iconst_1", "b", null, T_INT, 1); + def(ICONST_2, "iconst_2", "b", null, T_INT, 1); + def(ICONST_3, "iconst_3", "b", null, T_INT, 1); + def(ICONST_4, "iconst_4", "b", null, T_INT, 1); + def(ICONST_5, "iconst_5", "b", null, T_INT, 1); + def(LCONST_0, "lconst_0", "b", null, T_LONG, 2); + def(LCONST_1, "lconst_1", "b", null, T_LONG, 2); + def(FCONST_0, "fconst_0", "b", null, T_FLOAT, 1); + def(FCONST_1, "fconst_1", "b", null, T_FLOAT, 1); + def(FCONST_2, "fconst_2", "b", null, T_FLOAT, 1); + def(DCONST_0, "dconst_0", "b", null, T_DOUBLE, 2); + def(DCONST_1, "dconst_1", "b", null, T_DOUBLE, 2); + def(BIPUSH, "bipush", "bc", null, T_INT, 1); + def(SIPUSH, "sipush", "bcc", null, T_INT, 1); + def(LDC, "ldc", "bk", null, T_ILLEGAL, 1); + def(LDC_W, "ldc_w", "bkk", null, T_ILLEGAL, 1); + def(LDC2_W, "ldc2_w", "bkk", null, T_ILLEGAL, 2); + def(ILOAD, "iload", "bi", "wbii", T_INT, 1); + def(LLOAD, "lload", "bi", "wbii", T_LONG, 2); + def(FLOAD, "fload", "bi", "wbii", T_FLOAT, 1); + def(DLOAD, "dload", "bi", "wbii", T_DOUBLE, 2); + def(ALOAD, "aload", "bi", "wbii", T_OBJECT, 1); + def(ILOAD_0, "iload_0", "b", null, T_INT, 1); + def(ILOAD_1, "iload_1", "b", null, T_INT, 1); + def(ILOAD_2, "iload_2", "b", null, T_INT, 1); + def(ILOAD_3, "iload_3", "b", null, T_INT, 1); + def(LLOAD_0, "lload_0", "b", null, T_LONG, 2); + def(LLOAD_1, "lload_1", "b", null, T_LONG, 2); + def(LLOAD_2, "lload_2", "b", null, T_LONG, 2); + def(LLOAD_3, "lload_3", "b", null, T_LONG, 2); + def(FLOAD_0, "fload_0", "b", null, T_FLOAT, 1); + def(FLOAD_1, "fload_1", "b", null, T_FLOAT, 1); + def(FLOAD_2, "fload_2", "b", null, T_FLOAT, 1); + def(FLOAD_3, "fload_3", "b", null, T_FLOAT, 1); + def(DLOAD_0, "dload_0", "b", null, T_DOUBLE, 2); + def(DLOAD_1, "dload_1", "b", null, T_DOUBLE, 2); + def(DLOAD_2, "dload_2", "b", null, T_DOUBLE, 2); + def(DLOAD_3, "dload_3", "b", null, T_DOUBLE, 2); + def(ALOAD_0, "aload_0", "b", null, T_OBJECT, 1); + def(ALOAD_1, "aload_1", "b", null, T_OBJECT, 1); + def(ALOAD_2, "aload_2", "b", null, T_OBJECT, 1); + def(ALOAD_3, "aload_3", "b", null, T_OBJECT, 1); + def(IALOAD, "iaload", "b", null, T_INT, -1); + def(LALOAD, "laload", "b", null, T_LONG, 0); + def(FALOAD, "faload", "b", null, T_FLOAT, -1); + def(DALOAD, "daload", "b", null, T_DOUBLE, 0); + def(AALOAD, "aaload", "b", null, T_OBJECT, -1); + def(BALOAD, "baload", "b", null, T_INT, -1); + def(CALOAD, "caload", "b", null, T_INT, -1); + def(SALOAD, "saload", "b", null, T_INT, -1); + def(ISTORE, "istore", "bi", "wbii", T_VOID, -1); + def(LSTORE, "lstore", "bi", "wbii", T_VOID, -2); + def(FSTORE, "fstore", "bi", "wbii", T_VOID, -1); + def(DSTORE, "dstore", "bi", "wbii", T_VOID, -2); + def(ASTORE, "astore", "bi", "wbii", T_VOID, -1); + def(ISTORE_0, "istore_0", "b", null, T_VOID, -1); + def(ISTORE_1, "istore_1", "b", null, T_VOID, -1); + def(ISTORE_2, "istore_2", "b", null, T_VOID, -1); + def(ISTORE_3, "istore_3", "b", null, T_VOID, -1); + def(LSTORE_0, "lstore_0", "b", null, T_VOID, -2); + def(LSTORE_1, "lstore_1", "b", null, T_VOID, -2); + def(LSTORE_2, "lstore_2", "b", null, T_VOID, -2); + def(LSTORE_3, "lstore_3", "b", null, T_VOID, -2); + def(FSTORE_0, "fstore_0", "b", null, T_VOID, -1); + def(FSTORE_1, "fstore_1", "b", null, T_VOID, -1); + def(FSTORE_2, "fstore_2", "b", null, T_VOID, -1); + def(FSTORE_3, "fstore_3", "b", null, T_VOID, -1); + def(DSTORE_0, "dstore_0", "b", null, T_VOID, -2); + def(DSTORE_1, "dstore_1", "b", null, T_VOID, -2); + def(DSTORE_2, "dstore_2", "b", null, T_VOID, -2); + def(DSTORE_3, "dstore_3", "b", null, T_VOID, -2); + def(ASTORE_0, "astore_0", "b", null, T_VOID, -1); + def(ASTORE_1, "astore_1", "b", null, T_VOID, -1); + def(ASTORE_2, "astore_2", "b", null, T_VOID, -1); + def(ASTORE_3, "astore_3", "b", null, T_VOID, -1); + def(IASTORE, "iastore", "b", null, T_VOID, -3); + def(LASTORE, "lastore", "b", null, T_VOID, -4); + def(FASTORE, "fastore", "b", null, T_VOID, -3); + def(DASTORE, "dastore", "b", null, T_VOID, -4); + def(AASTORE, "aastore", "b", null, T_VOID, -3); + def(BASTORE, "bastore", "b", null, T_VOID, -3); + def(CASTORE, "castore", "b", null, T_VOID, -3); + def(SASTORE, "sastore", "b", null, T_VOID, -3); + def(POP, "pop", "b", null, T_VOID, -1); + def(POP2, "pop2", "b", null, T_VOID, -2); + def(DUP, "dup", "b", null, T_VOID, 1); + def(DUP_X1, "dup_x1", "b", null, T_VOID, 1); + def(DUP_X2, "dup_x2", "b", null, T_VOID, 1); + def(DUP2, "dup2", "b", null, T_VOID, 2); + def(DUP2_X1, "dup2_x1", "b", null, T_VOID, 2); + def(DUP2_X2, "dup2_x2", "b", null, T_VOID, 2); + def(SWAP, "swap", "b", null, T_VOID, 0); + def(IADD, "iadd", "b", null, T_INT, -1); + def(LADD, "ladd", "b", null, T_LONG, -2); + def(FADD, "fadd", "b", null, T_FLOAT, -1); + def(DADD, "dadd", "b", null, T_DOUBLE, -2); + def(ISUB, "isub", "b", null, T_INT, -1); + def(LSUB, "lsub", "b", null, T_LONG, -2); + def(FSUB, "fsub", "b", null, T_FLOAT, -1); + def(DSUB, "dsub", "b", null, T_DOUBLE, -2); + def(IMUL, "imul", "b", null, T_INT, -1); + def(LMUL, "lmul", "b", null, T_LONG, -2); + def(FMUL, "fmul", "b", null, T_FLOAT, -1); + def(DMUL, "dmul", "b", null, T_DOUBLE, -2); + def(IDIV, "idiv", "b", null, T_INT, -1); + def(LDIV, "ldiv", "b", null, T_LONG, -2); + def(FDIV, "fdiv", "b", null, T_FLOAT, -1); + def(DDIV, "ddiv", "b", null, T_DOUBLE, -2); + def(IREM, "irem", "b", null, T_INT, -1); + def(LREM, "lrem", "b", null, T_LONG, -2); + def(FREM, "frem", "b", null, T_FLOAT, -1); + def(DREM, "drem", "b", null, T_DOUBLE, -2); + def(INEG, "ineg", "b", null, T_INT, 0); + def(LNEG, "lneg", "b", null, T_LONG, 0); + def(FNEG, "fneg", "b", null, T_FLOAT, 0); + def(DNEG, "dneg", "b", null, T_DOUBLE, 0); + def(ISHL, "ishl", "b", null, T_INT, -1); + def(LSHL, "lshl", "b", null, T_LONG, -1); + def(ISHR, "ishr", "b", null, T_INT, -1); + def(LSHR, "lshr", "b", null, T_LONG, -1); + def(IUSHR, "iushr", "b", null, T_INT, -1); + def(LUSHR, "lushr", "b", null, T_LONG, -1); + def(IAND, "iand", "b", null, T_INT, -1); + def(LAND, "land", "b", null, T_LONG, -2); + def(IOR, "ior", "b", null, T_INT, -1); + def(LOR, "lor", "b", null, T_LONG, -2); + def(IXOR, "ixor", "b", null, T_INT, -1); + def(LXOR, "lxor", "b", null, T_LONG, -2); + def(IINC, "iinc", "bic", "wbiicc", T_VOID, 0); + def(I2L, "i2l", "b", null, T_LONG, 1); + def(I2F, "i2f", "b", null, T_FLOAT, 0); + def(I2D, "i2d", "b", null, T_DOUBLE, 1); + def(L2I, "l2i", "b", null, T_INT, -1); + def(L2F, "l2f", "b", null, T_FLOAT, -1); + def(L2D, "l2d", "b", null, T_DOUBLE, 0); + def(F2I, "f2i", "b", null, T_INT, 0); + def(F2L, "f2l", "b", null, T_LONG, 1); + def(F2D, "f2d", "b", null, T_DOUBLE, 1); + def(D2I, "d2i", "b", null, T_INT, -1); + def(D2L, "d2l", "b", null, T_LONG, 0); + def(D2F, "d2f", "b", null, T_FLOAT, -1); + def(I2B, "i2b", "b", null, T_BYTE, 0); + def(I2C, "i2c", "b", null, T_CHAR, 0); + def(I2S, "i2s", "b", null, T_SHORT, 0); + def(LCMP, "lcmp", "b", null, T_VOID, -3); + def(FCMPL, "fcmpl", "b", null, T_VOID, -1); + def(FCMPG, "fcmpg", "b", null, T_VOID, -1); + def(DCMPL, "dcmpl", "b", null, T_VOID, -3); + def(DCMPG, "dcmpg", "b", null, T_VOID, -3); + def(IFEQ, "ifeq", "boo", null, T_VOID, -1); + def(IFNE, "ifne", "boo", null, T_VOID, -1); + def(IFLT, "iflt", "boo", null, T_VOID, -1); + def(IFGE, "ifge", "boo", null, T_VOID, -1); + def(IFGT, "ifgt", "boo", null, T_VOID, -1); + def(IFLE, "ifle", "boo", null, T_VOID, -1); + def(IF_ICMPEQ, "if_icmpeq", "boo", null, T_VOID, -2); + def(IF_ICMPNE, "if_icmpne", "boo", null, T_VOID, -2); + def(IF_ICMPLT, "if_icmplt", "boo", null, T_VOID, -2); + def(IF_ICMPGE, "if_icmpge", "boo", null, T_VOID, -2); + def(IF_ICMPGT, "if_icmpgt", "boo", null, T_VOID, -2); + def(IF_ICMPLE, "if_icmple", "boo", null, T_VOID, -2); + def(IF_ACMPEQ, "if_acmpeq", "boo", null, T_VOID, -2); + def(IF_ACMPNE, "if_acmpne", "boo", null, T_VOID, -2); + def(GOTO, "goto", "boo", null, T_VOID, 0); + def(JSR, "jsr", "boo", null, T_INT, 0); + def(RET, "ret", "bi", "wbii", T_VOID, 0); + def(TABLESWITCH, "tableswitch", "", null, T_VOID, -1); // may have backward branches + def(LOOKUPSWITCH, "lookupswitch", "", null, T_VOID, -1); // rewriting in interpreter + def(IRETURN, "ireturn", "b", null, T_INT, -1); + def(LRETURN, "lreturn", "b", null, T_LONG, -2); + def(FRETURN, "freturn", "b", null, T_FLOAT, -1); + def(DRETURN, "dreturn", "b", null, T_DOUBLE, -2); + def(ARETURN, "areturn", "b", null, T_OBJECT, -1); + def(RETURN, "return", "b", null, T_VOID, 0); + def(GETSTATIC, "getstatic", "bJJ", null, T_ILLEGAL, 1); + def(PUTSTATIC, "putstatic", "bJJ", null, T_ILLEGAL, -1); + def(GETFIELD, "getfield", "bJJ", null, T_ILLEGAL, 0); + def(PUTFIELD, "putfield", "bJJ", null, T_ILLEGAL, -2); + def(INVOKEVIRTUAL, "invokevirtual", "bJJ", null, T_ILLEGAL, -1); + def(INVOKESPECIAL, "invokespecial", "bJJ", null, T_ILLEGAL, -1); + def(INVOKESTATIC, "invokestatic", "bJJ", null, T_ILLEGAL, 0); + def(INVOKEINTERFACE, "invokeinterface", "bJJ__", null, T_ILLEGAL, -1); + def(INVOKEDYNAMIC, "invokedynamic", "bJJJJ", null, T_ILLEGAL, 0); + def(NEW, "new", "bkk", null, T_OBJECT, 1); + def(NEWARRAY, "newarray", "bc", null, T_OBJECT, 0); + def(ANEWARRAY, "anewarray", "bkk", null, T_OBJECT, 0); + def(ARRAYLENGTH, "arraylength", "b", null, T_VOID, 0); + def(ATHROW, "athrow", "b", null, T_VOID, -1); + def(CHECKCAST, "checkcast", "bkk", null, T_OBJECT, 0); + def(INSTANCEOF, "instanceof", "bkk", null, T_INT, 0); + def(MONITORENTER, "monitorenter", "b", null, T_VOID, -1); + def(MONITOREXIT, "monitorexit", "b", null, T_VOID, -1); + def(WIDE, "wide", "", null, T_VOID, 0); + def(MULTIANEWARRAY, "multianewarray", "bkkc", null, T_OBJECT, 1); + def(IFNULL, "ifnull", "boo", null, T_VOID, -1); + def(IFNONNULL, "ifnonnull", "boo", null, T_VOID, -1); + def(GOTO_W, "goto_w", "boooo", null, T_VOID, 0); + def(JSR_W, "jsr_w", "boooo", null, T_INT, 0); def(_breakpoint, "breakpoint", "", null, T_VOID, 0); - def(_fast_agetfield, "fast_agetfield", "bJJ", null, T_OBJECT, 0, ClassFile.GETFIELD); - def(_fast_bgetfield, "fast_bgetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); - def(_fast_cgetfield, "fast_cgetfield", "bJJ", null, T_CHAR, 0, ClassFile.GETFIELD); - def(_fast_dgetfield, "fast_dgetfield", "bJJ", null, T_DOUBLE, 0, ClassFile.GETFIELD); - def(_fast_fgetfield, "fast_fgetfield", "bJJ", null, T_FLOAT, 0, ClassFile.GETFIELD); - def(_fast_igetfield, "fast_igetfield", "bJJ", null, T_INT, 0, ClassFile.GETFIELD); - def(_fast_lgetfield, "fast_lgetfield", "bJJ", null, T_LONG, 0, ClassFile.GETFIELD); - def(_fast_sgetfield, "fast_sgetfield", "bJJ", null, T_SHORT, 0, ClassFile.GETFIELD); - def(_fast_aputfield, "fast_aputfield", "bJJ", null, T_OBJECT, 0, ClassFile.PUTFIELD); - def(_fast_bputfield, "fast_bputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_zputfield, "fast_zputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_cputfield, "fast_cputfield", "bJJ", null, T_CHAR, 0, ClassFile.PUTFIELD); - def(_fast_dputfield, "fast_dputfield", "bJJ", null, T_DOUBLE, 0, ClassFile.PUTFIELD); - def(_fast_fputfield, "fast_fputfield", "bJJ", null, T_FLOAT, 0, ClassFile.PUTFIELD); - def(_fast_iputfield, "fast_iputfield", "bJJ", null, T_INT, 0, ClassFile.PUTFIELD); - def(_fast_lputfield, "fast_lputfield", "bJJ", null, T_LONG, 0, ClassFile.PUTFIELD); - def(_fast_sputfield, "fast_sputfield", "bJJ", null, T_SHORT, 0, ClassFile.PUTFIELD); - def(_fast_aload_0, "fast_aload_0", "b", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_iaccess_0, "fast_iaccess_0", "b_JJ", null, T_INT, 1, ClassFile.ALOAD_0); - def(_fast_aaccess_0, "fast_aaccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_faccess_0, "fast_faccess_0", "b_JJ", null, T_OBJECT, 1, ClassFile.ALOAD_0); - def(_fast_iload, "fast_iload", "bi", null, T_INT, 1, ClassFile.ILOAD); - def(_fast_iload2, "fast_iload2", "bi_i", null, T_INT, 2, ClassFile.ILOAD); - def(_fast_icaload, "fast_icaload", "bi_", null, T_INT, 0, ClassFile.ILOAD); - def(_fast_invokevfinal, "fast_invokevfinal", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); - def(_fast_linearswitch, "fast_linearswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); - def(_fast_binaryswitch, "fast_binaryswitch", "", null, T_VOID, -1, ClassFile.LOOKUPSWITCH); - def(_return_register_finalizer, "return_register_finalizer", "b", null, T_VOID, 0, ClassFile.RETURN); - def(_invokehandle, "invokehandle", "bJJ", null, T_ILLEGAL, -1, ClassFile.INVOKEVIRTUAL); - def(_fast_aldc, "fast_aldc", "bj", null, T_OBJECT, 1, ClassFile.LDC); - def(_fast_aldc_w, "fast_aldc_w", "bJJ", null, T_OBJECT, 1, ClassFile.LDC_W); - def(_nofast_getfield, "nofast_getfield", "bJJ", null, T_ILLEGAL, 0, ClassFile.GETFIELD); - def(_nofast_putfield, "nofast PUTFIELD", "bJJ", null, T_ILLEGAL, -2, ClassFile.PUTFIELD); - def(_nofast_aload_0, "nofast_aload_0", "b", null, T_ILLEGAL, 1, ClassFile.ALOAD_0); - def(_nofast_iload, "nofast_iload", "bi", null, T_ILLEGAL, 1, ClassFile.ILOAD); + def(_fast_agetfield, "fast_agetfield", "bJJ", null, T_OBJECT, 0, GETFIELD); + def(_fast_bgetfield, "fast_bgetfield", "bJJ", null, T_INT, 0, GETFIELD); + def(_fast_cgetfield, "fast_cgetfield", "bJJ", null, T_CHAR, 0, GETFIELD); + def(_fast_dgetfield, "fast_dgetfield", "bJJ", null, T_DOUBLE, 0, GETFIELD); + def(_fast_fgetfield, "fast_fgetfield", "bJJ", null, T_FLOAT, 0, GETFIELD); + def(_fast_igetfield, "fast_igetfield", "bJJ", null, T_INT, 0, GETFIELD); + def(_fast_lgetfield, "fast_lgetfield", "bJJ", null, T_LONG, 0, GETFIELD); + def(_fast_sgetfield, "fast_sgetfield", "bJJ", null, T_SHORT, 0, GETFIELD); + def(_fast_aputfield, "fast_aputfield", "bJJ", null, T_OBJECT, 0, PUTFIELD); + def(_fast_bputfield, "fast_bputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_zputfield, "fast_zputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_cputfield, "fast_cputfield", "bJJ", null, T_CHAR, 0, PUTFIELD); + def(_fast_dputfield, "fast_dputfield", "bJJ", null, T_DOUBLE, 0, PUTFIELD); + def(_fast_fputfield, "fast_fputfield", "bJJ", null, T_FLOAT, 0, PUTFIELD); + def(_fast_iputfield, "fast_iputfield", "bJJ", null, T_INT, 0, PUTFIELD); + def(_fast_lputfield, "fast_lputfield", "bJJ", null, T_LONG, 0, PUTFIELD); + def(_fast_sputfield, "fast_sputfield", "bJJ", null, T_SHORT, 0, PUTFIELD); + def(_fast_aload_0, "fast_aload_0", "b", null, T_OBJECT, 1, ALOAD_0); + def(_fast_iaccess_0, "fast_iaccess_0", "b_JJ", null, T_INT, 1, ALOAD_0); + def(_fast_aaccess_0, "fast_aaccess_0", "b_JJ", null, T_OBJECT, 1, ALOAD_0); + def(_fast_faccess_0, "fast_faccess_0", "b_JJ", null, T_OBJECT, 1, ALOAD_0); + def(_fast_iload, "fast_iload", "bi", null, T_INT, 1, ILOAD); + def(_fast_iload2, "fast_iload2", "bi_i", null, T_INT, 2, ILOAD); + def(_fast_icaload, "fast_icaload", "bi_", null, T_INT, 0, ILOAD); + def(_fast_invokevfinal, "fast_invokevfinal", "bJJ", null, T_ILLEGAL, -1, INVOKEVIRTUAL); + def(_fast_linearswitch, "fast_linearswitch", "", null, T_VOID, -1, LOOKUPSWITCH); + def(_fast_binaryswitch, "fast_binaryswitch", "", null, T_VOID, -1, LOOKUPSWITCH); + def(_return_register_finalizer, "return_register_finalizer", "b", null, T_VOID, 0, RETURN); + def(_invokehandle, "invokehandle", "bJJ", null, T_ILLEGAL, -1, INVOKEVIRTUAL); + def(_fast_aldc, "fast_aldc", "bj", null, T_OBJECT, 1, LDC); + def(_fast_aldc_w, "fast_aldc_w", "bJJ", null, T_OBJECT, 1, LDC_W); + def(_nofast_getfield, "nofast_getfield", "bJJ", null, T_ILLEGAL, 0, GETFIELD); + def(_nofast_putfield, "nofast PUTFIELD", "bJJ", null, T_ILLEGAL, -2, PUTFIELD); + def(_nofast_aload_0, "nofast_aload_0", "b", null, T_ILLEGAL, 1, ALOAD_0); + def(_nofast_iload, "nofast_iload", "bi", null, T_ILLEGAL, 1, ILOAD); def(_shouldnotreachhere, "_shouldnotreachhere", "b", null, T_VOID, 0); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java index 9a0e781d1458a..f41647788a175 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/verifier/VerifierImpl.java @@ -31,10 +31,9 @@ import java.lang.classfile.ClassHierarchyResolver; import java.lang.classfile.ClassModel; import java.lang.classfile.components.ClassPrinter; -import java.lang.classfile.ClassFile; import jdk.internal.classfile.impl.ClassHierarchyImpl; import jdk.internal.classfile.impl.RawBytecodeHelper; -import static jdk.internal.classfile.impl.RawBytecodeHelper.ILLEGAL; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; import jdk.internal.classfile.impl.verifier.VerificationWrapper.ConstantPoolWrapper; import static jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType.*; import jdk.internal.classfile.impl.verifier.VerificationSignature.BasicType; @@ -340,12 +339,12 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType type, type2 = null; VerificationType atype; if (bcs.isWide()) { - if (opcode != ClassFile.IINC && opcode != ClassFile.ILOAD - && opcode != ClassFile.ALOAD && opcode != ClassFile.LLOAD - && opcode != ClassFile.ISTORE && opcode != ClassFile.ASTORE - && opcode != ClassFile.LSTORE && opcode != ClassFile.FLOAD - && opcode != ClassFile.DLOAD && opcode != ClassFile.FSTORE - && opcode != ClassFile.DSTORE) { + if (opcode != IINC && opcode != ILOAD + && opcode != ALOAD && opcode != LLOAD + && opcode != ISTORE && opcode != ASTORE + && opcode != LSTORE && opcode != FLOAD + && opcode != DLOAD && opcode != FSTORE + && opcode != DSTORE) { verifyError("Bad wide instruction"); } } @@ -354,107 +353,107 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verified_exc_handlers = true; } switch (opcode) { - case ClassFile.NOP : + case NOP : no_control_flow = false; break; - case ClassFile.ACONST_NULL : + case ACONST_NULL : current_frame.push_stack( VerificationType.null_type); no_control_flow = false; break; - case ClassFile.ICONST_M1 : - case ClassFile.ICONST_0 : - case ClassFile.ICONST_1 : - case ClassFile.ICONST_2 : - case ClassFile.ICONST_3 : - case ClassFile.ICONST_4 : - case ClassFile.ICONST_5 : + case ICONST_M1 : + case ICONST_0 : + case ICONST_1 : + case ICONST_2 : + case ICONST_3 : + case ICONST_4 : + case ICONST_5 : current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LCONST_0 : - case ClassFile.LCONST_1 : + case LCONST_0 : + case LCONST_1 : current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FCONST_0 : - case ClassFile.FCONST_1 : - case ClassFile.FCONST_2 : + case FCONST_0 : + case FCONST_1 : + case FCONST_2 : current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DCONST_0 : - case ClassFile.DCONST_1 : + case DCONST_0 : + case DCONST_1 : current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.SIPUSH : - case ClassFile.BIPUSH : + case SIPUSH : + case BIPUSH : current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LDC : + case LDC : verify_ldc( opcode, bcs.getIndexU1(), current_frame, cp, bci); no_control_flow = false; break; - case ClassFile.LDC_W : - case ClassFile.LDC2_W : + case LDC_W : + case LDC2_W : verify_ldc( opcode, bcs.getIndexU2(), current_frame, cp, bci); no_control_flow = false; break; - case ClassFile.ILOAD : + case ILOAD : verify_iload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ILOAD_0 : - case ClassFile.ILOAD_1 : - case ClassFile.ILOAD_2 : - case ClassFile.ILOAD_3 : - index = opcode - ClassFile.ILOAD_0; + case ILOAD_0 : + case ILOAD_1 : + case ILOAD_2 : + case ILOAD_3 : + index = opcode - ILOAD_0; verify_iload(index, current_frame); no_control_flow = false; break; - case ClassFile.LLOAD : + case LLOAD : verify_lload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.LLOAD_0 : - case ClassFile.LLOAD_1 : - case ClassFile.LLOAD_2 : - case ClassFile.LLOAD_3 : - index = opcode - ClassFile.LLOAD_0; + case LLOAD_0 : + case LLOAD_1 : + case LLOAD_2 : + case LLOAD_3 : + index = opcode - LLOAD_0; verify_lload(index, current_frame); no_control_flow = false; break; - case ClassFile.FLOAD : + case FLOAD : verify_fload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.FLOAD_0 : - case ClassFile.FLOAD_1 : - case ClassFile.FLOAD_2 : - case ClassFile.FLOAD_3 : - index = opcode - ClassFile.FLOAD_0; + case FLOAD_0 : + case FLOAD_1 : + case FLOAD_2 : + case FLOAD_3 : + index = opcode - FLOAD_0; verify_fload(index, current_frame); no_control_flow = false; break; - case ClassFile.DLOAD : + case DLOAD : verify_dload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.DLOAD_0 : - case ClassFile.DLOAD_1 : - case ClassFile.DLOAD_2 : - case ClassFile.DLOAD_3 : - index = opcode - ClassFile.DLOAD_0; + case DLOAD_0 : + case DLOAD_1 : + case DLOAD_2 : + case DLOAD_3 : + index = opcode - DLOAD_0; verify_dload(index, current_frame); no_control_flow = false; break; - case ClassFile.ALOAD : + case ALOAD : verify_aload(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ALOAD_0 : - case ClassFile.ALOAD_1 : - case ClassFile.ALOAD_2 : - case ClassFile.ALOAD_3 : - index = opcode - ClassFile.ALOAD_0; + case ALOAD_0 : + case ALOAD_1 : + case ALOAD_2 : + case ALOAD_3 : + index = opcode - ALOAD_0; verify_aload(index, current_frame); no_control_flow = false; break; - case ClassFile.IALOAD : + case IALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -465,7 +464,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.BALOAD : + case BALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -476,7 +475,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.CALOAD : + case CALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -487,7 +486,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.SALOAD : + case SALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -498,7 +497,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LALOAD : + case LALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -510,7 +509,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FALOAD : + case FALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -521,7 +520,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DALOAD : + case DALOAD : type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -533,7 +532,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.AALOAD : { + case AALOAD : { type = current_frame.pop_stack( VerificationType.integer_type); atype = current_frame.pop_stack( @@ -551,57 +550,57 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } no_control_flow = false; break; } - case ClassFile.ISTORE : + case ISTORE : verify_istore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ISTORE_0 : - case ClassFile.ISTORE_1 : - case ClassFile.ISTORE_2 : - case ClassFile.ISTORE_3 : - index = opcode - ClassFile.ISTORE_0; + case ISTORE_0 : + case ISTORE_1 : + case ISTORE_2 : + case ISTORE_3 : + index = opcode - ISTORE_0; verify_istore(index, current_frame); no_control_flow = false; break; - case ClassFile.LSTORE : + case LSTORE : verify_lstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.LSTORE_0 : - case ClassFile.LSTORE_1 : - case ClassFile.LSTORE_2 : - case ClassFile.LSTORE_3 : - index = opcode - ClassFile.LSTORE_0; + case LSTORE_0 : + case LSTORE_1 : + case LSTORE_2 : + case LSTORE_3 : + index = opcode - LSTORE_0; verify_lstore(index, current_frame); no_control_flow = false; break; - case ClassFile.FSTORE : + case FSTORE : verify_fstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.FSTORE_0 : - case ClassFile.FSTORE_1 : - case ClassFile.FSTORE_2 : - case ClassFile.FSTORE_3 : - index = opcode - ClassFile.FSTORE_0; + case FSTORE_0 : + case FSTORE_1 : + case FSTORE_2 : + case FSTORE_3 : + index = opcode - FSTORE_0; verify_fstore(index, current_frame); no_control_flow = false; break; - case ClassFile.DSTORE : + case DSTORE : verify_dstore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.DSTORE_0 : - case ClassFile.DSTORE_1 : - case ClassFile.DSTORE_2 : - case ClassFile.DSTORE_3 : - index = opcode - ClassFile.DSTORE_0; + case DSTORE_0 : + case DSTORE_1 : + case DSTORE_2 : + case DSTORE_3 : + index = opcode - DSTORE_0; verify_dstore(index, current_frame); no_control_flow = false; break; - case ClassFile.ASTORE : + case ASTORE : verify_astore(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.ASTORE_0 : - case ClassFile.ASTORE_1 : - case ClassFile.ASTORE_2 : - case ClassFile.ASTORE_3 : - index = opcode - ClassFile.ASTORE_0; + case ASTORE_0 : + case ASTORE_1 : + case ASTORE_2 : + case ASTORE_3 : + index = opcode - ASTORE_0; verify_astore(index, current_frame); no_control_flow = false; break; - case ClassFile.IASTORE : + case IASTORE : type = current_frame.pop_stack( VerificationType.integer_type); type2 = current_frame.pop_stack( @@ -612,7 +611,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.BASTORE : + case BASTORE : type = current_frame.pop_stack( VerificationType.integer_type); type2 = current_frame.pop_stack( @@ -623,7 +622,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.CASTORE : + case CASTORE : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack( @@ -634,7 +633,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.SASTORE : + case SASTORE : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack( @@ -645,7 +644,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.LASTORE : + case LASTORE : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -657,7 +656,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.FASTORE : + case FASTORE : current_frame.pop_stack( VerificationType.float_type); current_frame.pop_stack @@ -668,7 +667,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.DASTORE : + case DASTORE : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -680,7 +679,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.AASTORE : + case AASTORE : type = current_frame.pop_stack(object_type()); type2 = current_frame.pop_stack( VerificationType.integer_type); @@ -692,11 +691,11 @@ void verify_method(VerificationWrapper.MethodWrapper m) { } // 4938384: relaxed constraint in JVMS 3nd edition. no_control_flow = false; break; - case ClassFile.POP : + case POP : current_frame.pop_stack( VerificationType.category1_check); no_control_flow = false; break; - case ClassFile.POP2 : + case POP2 : type = current_frame.pop_stack(); if (type.is_category1(this)) { current_frame.pop_stack( @@ -708,13 +707,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Bad type"); } no_control_flow = false; break; - case ClassFile.DUP : + case DUP : type = current_frame.pop_stack( VerificationType.category1_check); current_frame.push_stack(type); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP_X1 : + case DUP_X1 : type = current_frame.pop_stack( VerificationType.category1_check); type2 = current_frame.pop_stack( @@ -723,7 +722,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP_X2 : + case DUP_X2 : { VerificationType type3 = null; type = current_frame.pop_stack( @@ -744,7 +743,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.DUP2 : + case DUP2 : type = current_frame.pop_stack(); if (type.is_category1(this)) { type2 = current_frame.pop_stack( @@ -760,7 +759,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.DUP2_X1 : + case DUP2_X1 : { VerificationType type3; type = current_frame.pop_stack(); @@ -782,7 +781,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.DUP2_X2 : + case DUP2_X2 : VerificationType type3, type4 = null; type = current_frame.pop_stack(); if (type.is_category1(this)) { @@ -811,7 +810,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type2); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.SWAP : + case SWAP : type = current_frame.pop_stack( VerificationType.category1_check); type2 = current_frame.pop_stack( @@ -819,39 +818,39 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); current_frame.push_stack(type2); no_control_flow = false; break; - case ClassFile.IADD : - case ClassFile.ISUB : - case ClassFile.IMUL : - case ClassFile.IDIV : - case ClassFile.IREM : - case ClassFile.ISHL : - case ClassFile.ISHR : - case ClassFile.IUSHR : - case ClassFile.IOR : - case ClassFile.IXOR : - case ClassFile.IAND : + case IADD : + case ISUB : + case IMUL : + case IDIV : + case IREM : + case ISHL : + case ISHR : + case IUSHR : + case IOR : + case IXOR : + case IAND : current_frame.pop_stack( VerificationType.integer_type); // fall through - case ClassFile.INEG : + case INEG : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LADD : - case ClassFile.LSUB : - case ClassFile.LMUL : - case ClassFile.LDIV : - case ClassFile.LREM : - case ClassFile.LAND : - case ClassFile.LOR : - case ClassFile.LXOR : + case LADD : + case LSUB : + case LMUL : + case LDIV : + case LREM : + case LAND : + case LOR : + case LXOR : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); // fall through - case ClassFile.LNEG : + case LNEG : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -859,9 +858,9 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.LSHL : - case ClassFile.LSHR : - case ClassFile.LUSHR : + case LSHL : + case LSHR : + case LUSHR : current_frame.pop_stack( VerificationType.integer_type); current_frame.pop_stack_2( @@ -871,30 +870,30 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.FADD : - case ClassFile.FSUB : - case ClassFile.FMUL : - case ClassFile.FDIV : - case ClassFile.FREM : + case FADD : + case FSUB : + case FMUL : + case FDIV : + case FREM : current_frame.pop_stack( VerificationType.float_type); // fall through - case ClassFile.FNEG : + case FNEG : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.DADD : - case ClassFile.DSUB : - case ClassFile.DMUL : - case ClassFile.DDIV : - case ClassFile.DREM : + case DADD : + case DSUB : + case DMUL : + case DDIV : + case DREM : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); // fall through - case ClassFile.DNEG : + case DNEG : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -902,44 +901,44 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.IINC : + case IINC : verify_iinc(bcs.getIndex(), current_frame); no_control_flow = false; break; - case ClassFile.I2L : + case I2L : type = current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.L2I : + case L2I : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.I2F : + case I2F : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.I2D : + case I2D : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.L2F : + case L2F : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.L2D : + case L2D : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -947,34 +946,34 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.F2I : + case F2I : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.F2L : + case F2L : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack_2( VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.F2D : + case F2D : current_frame.pop_stack( VerificationType.float_type); current_frame.push_stack_2( VerificationType.double_type, VerificationType.double2_type); no_control_flow = false; break; - case ClassFile.D2I : + case D2I : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.D2L : + case D2L : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -982,22 +981,22 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.long_type, VerificationType.long2_type); no_control_flow = false; break; - case ClassFile.D2F : + case D2F : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); current_frame.push_stack( VerificationType.float_type); no_control_flow = false; break; - case ClassFile.I2B : - case ClassFile.I2C : - case ClassFile.I2S : + case I2B : + case I2C : + case I2S : current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.LCMP : + case LCMP : current_frame.pop_stack_2( VerificationType.long2_type, VerificationType.long_type); @@ -1007,8 +1006,8 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.FCMPL : - case ClassFile.FCMPG : + case FCMPL : + case FCMPG : current_frame.pop_stack( VerificationType.float_type); current_frame.pop_stack( @@ -1016,8 +1015,8 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.DCMPL : - case ClassFile.DCMPG : + case DCMPL : + case DCMPG : current_frame.pop_stack_2( VerificationType.double2_type, VerificationType.double_type); @@ -1027,63 +1026,63 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.IF_ICMPEQ: - case ClassFile.IF_ICMPNE: - case ClassFile.IF_ICMPLT: - case ClassFile.IF_ICMPGE: - case ClassFile.IF_ICMPGT: - case ClassFile.IF_ICMPLE: + case IF_ICMPEQ: + case IF_ICMPNE: + case IF_ICMPLT: + case IF_ICMPGE: + case IF_ICMPGT: + case IF_ICMPLE: current_frame.pop_stack( VerificationType.integer_type); // fall through - case ClassFile.IFEQ: - case ClassFile.IFNE: - case ClassFile.IFLT: - case ClassFile.IFGE: - case ClassFile.IFGT: - case ClassFile.IFLE: + case IFEQ: + case IFNE: + case IFLT: + case IFGE: + case IFGT: + case IFLE: current_frame.pop_stack( VerificationType.integer_type); target = bcs.dest(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = false; break; - case ClassFile.IF_ACMPEQ : - case ClassFile.IF_ACMPNE : + case IF_ACMPEQ : + case IF_ACMPNE : current_frame.pop_stack( VerificationType.reference_check); // fall through - case ClassFile.IFNULL : - case ClassFile.IFNONNULL : + case IFNULL : + case IFNONNULL : current_frame.pop_stack( VerificationType.reference_check); target = bcs.dest(); stackmap_table.check_jump_target (current_frame, target); no_control_flow = false; break; - case ClassFile.GOTO : + case GOTO : target = bcs.dest(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = true; break; - case ClassFile.GOTO_W : + case GOTO_W : target = bcs.destW(); stackmap_table.check_jump_target( current_frame, target); no_control_flow = true; break; - case ClassFile.TABLESWITCH : - case ClassFile.LOOKUPSWITCH : + case TABLESWITCH : + case LOOKUPSWITCH : verify_switch( bcs, code_length, code_data, current_frame, stackmap_table); no_control_flow = true; break; - case ClassFile.IRETURN : + case IRETURN : type = current_frame.pop_stack( VerificationType.integer_type); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.LRETURN : + case LRETURN : type2 = current_frame.pop_stack( VerificationType.long2_type); type = current_frame.pop_stack( @@ -1091,13 +1090,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.FRETURN : + case FRETURN : type = current_frame.pop_stack( VerificationType.float_type); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.DRETURN : + case DRETURN : type2 = current_frame.pop_stack( VerificationType.double2_type); type = current_frame.pop_stack( @@ -1105,13 +1104,13 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.ARETURN : + case ARETURN : type = current_frame.pop_stack( VerificationType.reference_check); verify_return_value(return_type, type, bci, current_frame); no_control_flow = true; break; - case ClassFile.RETURN: + case RETURN: if (!return_type.is_bogus()) { verifyError("Method expects a return value"); } @@ -1120,24 +1119,24 @@ void verify_method(VerificationWrapper.MethodWrapper m) { verifyError("Constructor must call super() or this() before return"); } no_control_flow = true; break; - case ClassFile.GETSTATIC : - case ClassFile.PUTSTATIC : + case GETSTATIC : + case PUTSTATIC : verify_field_instructions(bcs, current_frame, cp, true); no_control_flow = false; break; - case ClassFile.GETFIELD : - case ClassFile.PUTFIELD : + case GETFIELD : + case PUTFIELD : verify_field_instructions(bcs, current_frame, cp, false); no_control_flow = false; break; - case ClassFile.INVOKEVIRTUAL : - case ClassFile.INVOKESPECIAL : - case ClassFile.INVOKESTATIC : + case INVOKEVIRTUAL : + case INVOKESPECIAL : + case INVOKESTATIC : this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); no_control_flow = false; break; - case ClassFile.INVOKEINTERFACE : - case ClassFile.INVOKEDYNAMIC : + case INVOKEINTERFACE : + case INVOKEDYNAMIC : this_uninit = verify_invoke_instructions(bcs, code_length, current_frame, (bci >= ex_minmax[0] && bci < ex_minmax[1]), this_uninit, return_type, cp, stackmap_table); no_control_flow = false; break; - case ClassFile.NEW : + case NEW : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); @@ -1150,16 +1149,16 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(type); no_control_flow = false; break; } - case ClassFile.NEWARRAY : + case NEWARRAY : type = get_newarray_type(bcs.getIndex(), bci); current_frame.pop_stack( VerificationType.integer_type); current_frame.push_stack(type); no_control_flow = false; break; - case ClassFile.ANEWARRAY : + case ANEWARRAY : verify_anewarray(bci, bcs.getIndexU2(), cp, current_frame); no_control_flow = false; break; - case ClassFile.ARRAYLENGTH : + case ARRAYLENGTH : type = current_frame.pop_stack( VerificationType.reference_check); if (!(type.is_null() || type.is_array())) { @@ -1168,7 +1167,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack( VerificationType.integer_type); no_control_flow = false; break; - case ClassFile.CHECKCAST : + case CHECKCAST : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); @@ -1178,7 +1177,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(klass_type); no_control_flow = false; break; } - case ClassFile.INSTANCEOF : { + case INSTANCEOF : { index = bcs.getIndexU2(); verify_cp_class_type(bci, index, cp); current_frame.pop_stack(object_type()); @@ -1186,12 +1185,12 @@ void verify_method(VerificationWrapper.MethodWrapper m) { VerificationType.integer_type); no_control_flow = false; break; } - case ClassFile.MONITORENTER : - case ClassFile.MONITOREXIT : + case MONITORENTER : + case MONITOREXIT : current_frame.pop_stack( VerificationType.reference_check); no_control_flow = false; break; - case ClassFile.MULTIANEWARRAY : + case MULTIANEWARRAY : { index = bcs.getIndexU2(); int dim = _method.codeArray()[bcs.bci() +3] & 0xff; @@ -1211,7 +1210,7 @@ void verify_method(VerificationWrapper.MethodWrapper m) { current_frame.push_stack(new_array_type); no_control_flow = false; break; } - case ClassFile.ATHROW : + case ATHROW : type = VerificationType.reference_type(java_lang_Throwable); current_frame.pop_stack(type); no_control_flow = true; break; @@ -1235,7 +1234,7 @@ private byte[] generate_code_data(RawBytecodeHelper.CodeRange code) { while (bcs.next()) { if (bcs.opcode() != ILLEGAL) { int bci = bcs.bci(); - if (bcs.opcode() == ClassFile.NEW) { + if (bcs.opcode() == NEW) { code_data[bci] = NEW_OFFSET; } else { code_data[bci] = BYTECODE_OFFSET; @@ -1368,14 +1367,14 @@ void verify_ldc(int opcode, int index, VerificationFrame current_frame, Constant verify_cp_index(bci, cp, index); int tag = cp.tagAt(index); int types = 0; - if (opcode == ClassFile.LDC || opcode == ClassFile.LDC_W) { + if (opcode == LDC || opcode == LDC_W) { types = (1 << JVM_CONSTANT_Integer) | (1 << JVM_CONSTANT_Float) | (1 << JVM_CONSTANT_String) | (1 << JVM_CONSTANT_Class) | (1 << JVM_CONSTANT_MethodHandle) | (1 << JVM_CONSTANT_MethodType) | (1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); } else { - if (opcode != ClassFile.LDC2_W) verifyError("must be ldc2_w"); + if (opcode != LDC2_W) verifyError("must be ldc2_w"); types = (1 << JVM_CONSTANT_Double) | (1 << JVM_CONSTANT_Long) | (1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); } @@ -1395,7 +1394,7 @@ void verify_ldc(int opcode, int index, VerificationFrame current_frame, Constant VerificationType[] v_constant_type = new VerificationType[2]; var sig_stream = new VerificationSignature(constant_type, false, this); int n = change_sig_to_verificationType(sig_stream, v_constant_type, 0); - int opcode_n = (opcode == ClassFile.LDC2_W ? 2 : 1); + int opcode_n = (opcode == LDC2_W ? 2 : 1); if (n != opcode_n) { types &= ~(1 << JVM_CONSTANT_Dynamic); verify_cp_type(bci, index, cp, types); @@ -1424,7 +1423,7 @@ void verify_switch(RawBytecodeHelper bcs, int code_length, byte[] code_data, Ver int default_offset = bcs.getIntUnchecked(aligned_bci); int keys, delta; current_frame.pop_stack(VerificationType.integer_type); - if (bcs.opcode() == ClassFile.TABLESWITCH) { + if (bcs.opcode() == TABLESWITCH) { int low = bcs.getIntUnchecked(aligned_bci + 4); int high = bcs.getIntUnchecked(aligned_bci + 2*4); if (low > high) { @@ -1477,24 +1476,24 @@ void verify_field_instructions(RawBytecodeHelper bcs, VerificationFrame current_ int n = change_sig_to_verificationType(sig_stream, field_type, 0); boolean is_assignable; switch (bcs.opcode()) { - case ClassFile.GETSTATIC -> { + case GETSTATIC -> { for (int i = 0; i < n; i++) { current_frame.push_stack(field_type[i]); } } - case ClassFile.PUTSTATIC -> { + case PUTSTATIC -> { for (int i = n - 1; i >= 0; i--) { current_frame.pop_stack(field_type[i]); } } - case ClassFile.GETFIELD -> { + case GETFIELD -> { stack_object_type = current_frame.pop_stack( target_class_type); for (int i = 0; i < n; i++) { current_frame.push_stack(field_type[i]); } } - case ClassFile.PUTFIELD -> { + case PUTFIELD -> { for (int i = n - 1; i >= 0; i--) { current_frame.pop_stack(field_type[i]); } @@ -1548,7 +1547,7 @@ boolean verify_invoke_init(RawBytecodeHelper bcs, int ref_class_index, Verificat this_uninit = true; } else if (type.is_uninitialized()) { int new_offset = type.bci(this); - if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != ClassFile.NEW) { + if (new_offset > (code_length - 3) || (_method.codeArray()[new_offset] & 0xff) != NEW) { verifyError("Expecting new instruction"); } int new_class_index = bcs.getU2(new_offset + 1); @@ -1585,14 +1584,14 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif int opcode = bcs.opcode(); int types = 0; switch (opcode) { - case ClassFile.INVOKEINTERFACE: + case INVOKEINTERFACE: types = 1 << JVM_CONSTANT_InterfaceMethodref; break; - case ClassFile.INVOKEDYNAMIC: + case INVOKEDYNAMIC: types = 1 << JVM_CONSTANT_InvokeDynamic; break; - case ClassFile.INVOKESPECIAL: - case ClassFile.INVOKESTATIC: + case INVOKESPECIAL: + case INVOKESTATIC: types = (_klass.majorVersion() < STATIC_METHOD_IN_INTERFACE_MAJOR_VERSION) ? (1 << JVM_CONSTANT_Methodref) : ((1 << JVM_CONSTANT_InterfaceMethodref) | (1 << JVM_CONSTANT_Methodref)); @@ -1605,7 +1604,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif String method_sig = cp.refSignatureAt(index); if (!VerificationSignature.isValidMethodSignature(method_sig)) verifyError("Invalid method signature"); VerificationType ref_class_type = null; - if (opcode == ClassFile.INVOKEDYNAMIC) { + if (opcode == INVOKEDYNAMIC) { if (_klass.majorVersion() < INVOKEDYNAMIC_MAJOR_VERSION) { classError(String.format("invokedynamic instructions not supported by this class file version (%d), class %s", _klass.majorVersion(), _klass.thisClassName())); } @@ -1619,7 +1618,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif create_method_sig_entry(mth_sig_verif_types, sig); int nargs = mth_sig_verif_types.num_args(); int bci = bcs.bci(); - if (opcode == ClassFile.INVOKEINTERFACE) { + if (opcode == INVOKEINTERFACE) { if ((_method.codeArray()[bci+3] & 0xff) != (nargs+1)) { verifyError("Inconsistent args count operand in invokeinterface"); } @@ -1627,17 +1626,17 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif verifyError("Fourth operand byte of invokeinterface must be zero"); } } - if (opcode == ClassFile.INVOKEDYNAMIC) { + if (opcode == INVOKEDYNAMIC) { if ((_method.codeArray()[bci+3] & 0xff) != 0 || (_method.codeArray()[bci+4] & 0xff) != 0) { verifyError("Third and fourth operand bytes of invokedynamic must be zero"); } } if (method_name.charAt(0) == JVM_SIGNATURE_SPECIAL) { - if (opcode != ClassFile.INVOKESPECIAL || + if (opcode != INVOKESPECIAL || !object_initializer_name.equals(method_name)) { verifyError("Illegal call to internal method"); } - } else if (opcode == ClassFile.INVOKESPECIAL + } else if (opcode == INVOKESPECIAL && !is_same_or_direct_interface(current_class(), current_type(), ref_class_type) && !ref_class_type.equals(VerificationType.reference_type( current_class().superclassName()))) { @@ -1655,16 +1654,16 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif for (int i = nargs - 1; i >= 0; i--) { // Run backwards current_frame.pop_stack(sig_verif_types.get(i)); } - if (opcode != ClassFile.INVOKESTATIC && - opcode != ClassFile.INVOKEDYNAMIC) { + if (opcode != INVOKESTATIC && + opcode != INVOKEDYNAMIC) { if (object_initializer_name.equals(method_name)) { // method this_uninit = verify_invoke_init(bcs, index, ref_class_type, current_frame, code_length, in_try_block, this_uninit, cp, stackmap_table); } else { switch (opcode) { - case ClassFile.INVOKESPECIAL -> + case INVOKESPECIAL -> current_frame.pop_stack(current_type()); - case ClassFile.INVOKEVIRTUAL -> { + case INVOKEVIRTUAL -> { VerificationType stack_object_type = current_frame.pop_stack(ref_class_type); if (current_type() != stack_object_type) { @@ -1672,7 +1671,7 @@ boolean verify_invoke_instructions(RawBytecodeHelper bcs, int code_length, Verif } } default -> { - if (opcode != ClassFile.INVOKEINTERFACE) + if (opcode != INVOKEINTERFACE) verifyError("Unexpected opcode encountered"); current_frame.pop_stack(ref_class_type); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java index 4ff0df787c54f..432b324c1bd09 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/ConfinedSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.annotation.ForceInline; /** @@ -40,15 +41,8 @@ final class ConfinedSession extends MemorySessionImpl { private int asyncReleaseCount = 0; - static final VarHandle ASYNC_RELEASE_COUNT; - - static { - try { - ASYNC_RELEASE_COUNT = MethodHandles.lookup().findVarHandle(ConfinedSession.class, "asyncReleaseCount", int.class); - } catch (Throwable ex) { - throw new ExceptionInInitializerError(ex); - } - } + static final VarHandle ASYNC_RELEASE_COUNT= MhUtil.findVarHandle( + MethodHandles.lookup(), "asyncReleaseCount", int.class); public ConfinedSession(Thread owner) { super(owner, new ConfinedResourceList()); diff --git a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java index aef62be815160..a12b16ca8b4fa 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java +++ b/src/java.base/share/classes/jdk/internal/foreign/MemorySessionImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -36,6 +36,7 @@ import jdk.internal.foreign.GlobalSession.HeapSession; import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.annotation.ForceInline; /** @@ -57,7 +58,9 @@ public abstract sealed class MemorySessionImpl static final int OPEN = 0; static final int CLOSED = -1; - static final VarHandle STATE; + static final VarHandle STATE = MhUtil.findVarHandle( + MethodHandles.lookup(), "state", int.class); + static final int MAX_FORKS = Integer.MAX_VALUE; static final ScopedMemoryAccess.ScopedAccessError ALREADY_CLOSED = new ScopedMemoryAccess.ScopedAccessError(MemorySessionImpl::alreadyClosed); @@ -69,14 +72,6 @@ public abstract sealed class MemorySessionImpl final Thread owner; int state = OPEN; - static { - try { - STATE = MethodHandles.lookup().findVarHandle(MemorySessionImpl.class, "state", int.class); - } catch (Exception ex) { - throw new ExceptionInInitializerError(ex); - } - } - public Arena asArena() { return new ArenaImpl(this); } diff --git a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java index 1569589ef9b81..6c9666c2b58fc 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java +++ b/src/java.base/share/classes/jdk/internal/foreign/SharedSession.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -28,6 +28,7 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; import jdk.internal.misc.ScopedMemoryAccess; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.annotation.ForceInline; /** @@ -91,15 +92,8 @@ void justClose() { */ static class SharedResourceList extends ResourceList { - static final VarHandle FST; - - static { - try { - FST = MethodHandles.lookup().findVarHandle(ResourceList.class, "fst", ResourceCleanup.class); - } catch (Throwable ex) { - throw new ExceptionInInitializerError(); - } - } + static final VarHandle FST = MhUtil.findVarHandle( + MethodHandles.lookup(), ResourceList.class, "fst", ResourceCleanup.class); @Override void add(ResourceCleanup cleanup) { diff --git a/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java b/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java index 44fee62cb6fbe..c56cca3091221 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java +++ b/src/java.base/share/classes/jdk/internal/foreign/abi/DowncallLinker.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -26,6 +26,7 @@ import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; import sun.security.action.GetPropertyAction; import java.lang.foreign.AddressLayout; @@ -38,7 +39,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Map; import java.util.stream.Stream; import jdk.internal.foreign.AbstractMemorySegmentImpl; @@ -56,18 +56,11 @@ public class DowncallLinker { private static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); - private static final MethodHandle MH_INVOKE_INTERP_BINDINGS; - private static final MethodHandle EMPTY_OBJECT_ARRAY_HANDLE = MethodHandles.constant(Object[].class, new Object[0]); + private static final MethodHandle MH_INVOKE_INTERP_BINDINGS = MhUtil.findVirtual( + MethodHandles.lookup(), DowncallLinker.class, "invokeInterpBindings", + methodType(Object.class, SegmentAllocator.class, Object[].class, InvocationData.class)); - static { - try { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - MH_INVOKE_INTERP_BINDINGS = lookup.findVirtual(DowncallLinker.class, "invokeInterpBindings", - methodType(Object.class, SegmentAllocator.class, Object[].class, InvocationData.class)); - } catch (ReflectiveOperationException e) { - throw new RuntimeException(e); - } - } + private static final MethodHandle EMPTY_OBJECT_ARRAY_HANDLE = MethodHandles.constant(Object[].class, new Object[0]); private final ABIDescriptor abi; private final CallingSequence callingSequence; diff --git a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java index 796f0027158f1..b1821ba1d1afb 100644 --- a/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java +++ b/src/java.base/share/classes/jdk/internal/foreign/layout/AbstractLayout.java @@ -27,6 +27,7 @@ import jdk.internal.foreign.LayoutPath; import jdk.internal.foreign.Utils; +import jdk.internal.invoke.MhUtil; import java.lang.foreign.GroupLayout; import java.lang.foreign.MemoryLayout; @@ -157,15 +158,9 @@ public long scale(long offset, long index) { public MethodHandle scaleHandle() { class Holder { - static final MethodHandle MH_SCALE; - static { - try { - MH_SCALE = MethodHandles.lookup().findVirtual(MemoryLayout.class, "scale", - MethodType.methodType(long.class, long.class, long.class)); - } catch (ReflectiveOperationException e) { - throw new ExceptionInInitializerError(e); - } - } + static final MethodHandle MH_SCALE = MhUtil.findVirtual( + MethodHandles.lookup(), MemoryLayout.class, "scale", + MethodType.methodType(long.class, long.class, long.class)); } return Holder.MH_SCALE.bindTo(this); } diff --git a/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java b/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java new file mode 100644 index 0000000000000..16a4e10221c66 --- /dev/null +++ b/src/java.base/share/classes/jdk/internal/invoke/MhUtil.java @@ -0,0 +1,78 @@ +/* + * 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. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * 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. + */ + +package jdk.internal.invoke; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.invoke.VarHandle; + +/** + * Static factories for certain VarHandle/MethodHandle variants. + *

    + * The methods will throw an {@link InternalError} if the lookup fails. + *

    + * Here is an example of how one of these methods could be used: + * {@snippet lang=java + * static MethodHandle BAR_HANDLE = + * MhUtil.findVirtual(MethodHandles.lookup(), + * Foo.class,"bar",MethodType.methodType(int.class)); + * } + */ +public final class MhUtil { + + private MhUtil() {} + + public static VarHandle findVarHandle(MethodHandles.Lookup lookup, + String name, + Class type) { + return findVarHandle(lookup, lookup.lookupClass(), name, type); + } + + public static VarHandle findVarHandle(MethodHandles.Lookup lookup, + Class recv, + String name, + Class type) { + try { + return lookup.findVarHandle(recv, name, type); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + + + public static MethodHandle findVirtual(MethodHandles.Lookup lookup, + Class refc, + String name, + MethodType type) { + try { + return lookup.findVirtual(refc, name, type); + } catch (ReflectiveOperationException e) { + throw new InternalError(e); + } + } + +} diff --git a/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java b/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java index e9c75d4a3b2fc..8bf38b7973489 100644 --- a/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java +++ b/src/java.base/share/classes/jdk/internal/misc/ThreadFlock.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -36,6 +36,7 @@ import java.util.stream.Stream; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; import jdk.internal.vm.ScopedValueContainer; import jdk.internal.vm.ThreadContainer; import jdk.internal.vm.ThreadContainers; @@ -84,13 +85,9 @@ public class ThreadFlock implements AutoCloseable { private static final VarHandle THREAD_COUNT; private static final VarHandle PERMIT; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - THREAD_COUNT = l.findVarHandle(ThreadFlock.class, "threadCount", int.class); - PERMIT = l.findVarHandle(ThreadFlock.class, "permit", boolean.class); - } catch (Exception e) { - throw new InternalError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + THREAD_COUNT = MhUtil.findVarHandle(l, "threadCount", int.class); + PERMIT = MhUtil.findVarHandle(l, "permit", boolean.class); } private final Set threads = ConcurrentHashMap.newKeySet(); diff --git a/src/java.base/share/classes/jdk/internal/misc/VM.java b/src/java.base/share/classes/jdk/internal/misc/VM.java index de6f011fe8ffd..1c31ef5a184e2 100644 --- a/src/java.base/share/classes/jdk/internal/misc/VM.java +++ b/src/java.base/share/classes/jdk/internal/misc/VM.java @@ -28,6 +28,7 @@ import static java.lang.Thread.State.*; import java.io.PrintStream; +import java.lang.classfile.ClassFile; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -158,10 +159,6 @@ public static boolean isDirectMemoryPageAligned() { return pageAlignDirectMemory; } - private static int classFileMajorVersion; - private static int classFileMinorVersion; - private static final int PREVIEW_MINOR_VERSION = 65535; - /** * Tests if the given version is a supported {@code class} * file version. @@ -175,11 +172,11 @@ public static boolean isDirectMemoryPageAligned() { * @jvms 4.1 Table 4.1-A. class file format major versions */ public static boolean isSupportedClassFileVersion(int major, int minor) { - if (major < 45 || major > classFileMajorVersion) return false; + if (major < ClassFile.JAVA_1_VERSION || major > ClassFile.latestMajorVersion()) return false; // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; + if (major < ClassFile.JAVA_12_VERSION) return true; // otherwise, the minor version must be 0 or 65535 - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + return minor == 0 || (minor == ClassFile.PREVIEW_MINOR_VERSION && major == ClassFile.latestMajorVersion()); } /** @@ -189,12 +186,8 @@ public static boolean isSupportedClassFileVersion(int major, int minor) { * major.minor version >= 53.0 */ public static boolean isSupportedModuleDescriptorVersion(int major, int minor) { - if (major < 53 || major > classFileMajorVersion) return false; - // for major version is between 45 and 55 inclusive, the minor version may be any value - if (major < 56) return true; - // otherwise, the minor version must be 0 or 65535 - // preview features do not apply to module-info.class but JVMS allows it - return minor == 0 || minor == PREVIEW_MINOR_VERSION; + if (major < ClassFile.JAVA_9_VERSION) return false; + return isSupportedClassFileVersion(major, minor); } /** @@ -271,15 +264,6 @@ public static void saveProperties(Map props) { s = props.get("sun.nio.PageAlignDirectMemory"); if ("true".equals(s)) pageAlignDirectMemory = true; - - s = props.get("java.class.version"); - int index = s.indexOf('.'); - try { - classFileMajorVersion = Integer.parseInt(s.substring(0, index)); - classFileMinorVersion = Integer.parseInt(s.substring(index + 1)); - } catch (NumberFormatException e) { - throw new InternalError(e); - } } // Initialize any miscellaneous operating system settings that need to be diff --git a/src/java.base/share/classes/jdk/internal/reflect/DirectMethodHandleAccessor.java b/src/java.base/share/classes/jdk/internal/reflect/DirectMethodHandleAccessor.java index f345d4cdb712c..54f0c7c563d47 100644 --- a/src/java.base/share/classes/jdk/internal/reflect/DirectMethodHandleAccessor.java +++ b/src/java.base/share/classes/jdk/internal/reflect/DirectMethodHandleAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -27,6 +27,7 @@ import jdk.internal.access.JavaLangInvokeAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; import jdk.internal.misc.VM; import jdk.internal.vm.annotation.ForceInline; import jdk.internal.vm.annotation.Hidden; @@ -310,17 +311,10 @@ static Object invoke(MethodHandle target, Class caller, Object obj, Object[] } } - static final JavaLangInvokeAccess JLIA; - static final MethodHandle NATIVE_ACCESSOR_INVOKE; - static { - try { - JLIA = SharedSecrets.getJavaLangInvokeAccess(); - NATIVE_ACCESSOR_INVOKE = MethodHandles.lookup().findVirtual(NativeAccessor.class, "invoke", - genericMethodType(1, true)); - } catch (NoSuchMethodException|IllegalAccessException e) { - throw new InternalError(e); - } - } + static final JavaLangInvokeAccess JLIA = SharedSecrets.getJavaLangInvokeAccess(); + static final MethodHandle NATIVE_ACCESSOR_INVOKE = MhUtil.findVirtual( + MethodHandles.lookup(), NativeAccessor.class, "invoke", + genericMethodType(1, true)); } } diff --git a/src/java.base/share/classes/jdk/internal/vm/SharedThreadContainer.java b/src/java.base/share/classes/jdk/internal/vm/SharedThreadContainer.java index 36933ad676918..ef9796b0c7d4a 100644 --- a/src/java.base/share/classes/jdk/internal/vm/SharedThreadContainer.java +++ b/src/java.base/share/classes/jdk/internal/vm/SharedThreadContainer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -31,6 +31,7 @@ import java.util.stream.Stream; import jdk.internal.access.JavaLangAccess; import jdk.internal.access.SharedSecrets; +import jdk.internal.invoke.MhUtil; /** * A "shared" thread container. A shared thread container doesn't have an owner @@ -41,15 +42,9 @@ public class SharedThreadContainer extends ThreadContainer implements AutoClosea private static final VarHandle CLOSED; private static final VarHandle VIRTUAL_THREADS; static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - CLOSED = l.findVarHandle(SharedThreadContainer.class, - "closed", boolean.class); - VIRTUAL_THREADS = l.findVarHandle(SharedThreadContainer.class, - "virtualThreads", Set.class); - } catch (Exception e) { - throw new ExceptionInInitializerError(e); - } + MethodHandles.Lookup l = MethodHandles.lookup(); + CLOSED = MhUtil.findVarHandle(l, "closed", boolean.class); + VIRTUAL_THREADS = MhUtil.findVarHandle(l, "virtualThreads", Set.class); } // name of container, used by toString diff --git a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java index 5fac688b3115e..9f85aec7cd39a 100644 --- a/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java +++ b/src/java.base/share/classes/sun/nio/ch/DatagramChannelImpl.java @@ -68,13 +68,13 @@ import java.util.Map; import java.util.Objects; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.function.Consumer; import jdk.internal.access.JavaNioAccess; import jdk.internal.access.SharedSecrets; import jdk.internal.ref.CleanerFactory; +import jdk.internal.invoke.MhUtil; import sun.net.ResourceManager; import sun.net.ext.ExtendedSocketOptions; import sun.net.util.IPAddressUtil; @@ -149,15 +149,8 @@ class DatagramChannelImpl private InetSocketAddress initialLocalAddress; // Socket adaptor, created lazily - private static final VarHandle SOCKET; - static { - try { - MethodHandles.Lookup l = MethodHandles.lookup(); - SOCKET = l.findVarHandle(DatagramChannelImpl.class, "socket", DatagramSocket.class); - } catch (Exception e) { - throw new InternalError(e); - } - } + private static final VarHandle SOCKET = MhUtil.findVarHandle( + MethodHandles.lookup(), "socket", DatagramSocket.class); private volatile DatagramSocket socket; // Multicast support diff --git a/src/java.base/share/classes/sun/security/tools/keytool/Main.java b/src/java.base/share/classes/sun/security/tools/keytool/Main.java index 00e40c5f58761..3afd5b2142a5c 100644 --- a/src/java.base/share/classes/sun/security/tools/keytool/Main.java +++ b/src/java.base/share/classes/sun/security/tools/keytool/Main.java @@ -1132,7 +1132,6 @@ && isKeyStoreRelated(command) } } - KeyStore cakstore = buildTrustedCerts(); // -trustcacerts can be specified on -importcert, -printcert or -printcrl. // Reset it so that warnings on CA cert will remain for other command. if (command != IMPORTCERT && command != PRINTCERT @@ -1141,6 +1140,7 @@ && isKeyStoreRelated(command) } if (trustcacerts) { + KeyStore cakstore = buildTrustedCerts(); if (cakstore != null) { caks = cakstore; } else { diff --git a/src/java.base/share/classes/sun/security/util/PropertyExpander.java b/src/java.base/share/classes/sun/security/util/PropertyExpander.java index 2cc4929e04bbc..e92d57bfee22d 100644 --- a/src/java.base/share/classes/sun/security/util/PropertyExpander.java +++ b/src/java.base/share/classes/sun/security/util/PropertyExpander.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -28,6 +28,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.security.GeneralSecurityException; +import java.util.function.UnaryOperator; /** * A utility class to expand properties embedded in a string. @@ -51,15 +52,31 @@ public ExpandException(String msg) { } } - public static String expand(String value) - throws ExpandException - { + public static String expand(String value) throws ExpandException { return expand(value, false); } - public static String expand(String value, boolean encodeURL) - throws ExpandException - { + public static String expand(String value, boolean encodeURL) + throws ExpandException { + return expand(value, encodeURL, System::getProperty); + } + + /* + * In non-strict mode an undefined property is replaced by an empty string. + */ + public static String expandNonStrict(String value) { + try { + return expand(value, false, key -> System.getProperty(key, "")); + } catch (ExpandException e) { + // should not happen + throw new AssertionError("unexpected expansion error: when " + + "expansion is non-strict, undefined properties should " + + "be replaced by an empty string", e); + } + } + + private static String expand(String value, boolean encodeURL, + UnaryOperator propertiesGetter) throws ExpandException { if (value == null) return null; @@ -105,7 +122,7 @@ public static String expand(String value, boolean encodeURL) if (prop.equals("/")) { sb.append(java.io.File.separatorChar); } else { - String val = System.getProperty(prop); + String val = propertiesGetter.apply(prop); if (val != null) { if (encodeURL) { // encode 'val' unless it's an absolute URI diff --git a/src/java.base/share/conf/security/java.security b/src/java.base/share/conf/security/java.security index c537a30960e49..9651ae2d373d4 100644 --- a/src/java.base/share/conf/security/java.security +++ b/src/java.base/share/conf/security/java.security @@ -28,6 +28,33 @@ # Properties in this file are typically parsed only once. If any of the # properties are modified, applications should be restarted to ensure the # changes are properly reflected. +# +# The special "include" property can be defined one or multiple times with +# a filesystem path value. The effect of each definition is to include a +# referred security properties file inline, adding all its properties. +# Security properties defined before an include statement may be overridden +# by properties in the included file, if their names match. Conversely, +# properties defined after an include statement may override properties in +# the included file. +# +# Included files, as well as files pointed to by java.security.properties, +# can include other files recursively. Paths may be absolute or relative. +# Each relative path is resolved against the base file containing its +# "include" definition, if local. Paths may contain system properties for +# expansion in the form of ${system.property}. If a system property does +# not have a value, it expands to the empty string. +# +# An error will be thrown if a file cannot be included. This may happen +# if the file cannot be resolved, does not exist, is a directory, there are +# insufficient permissions to read it, it is recursively included more than +# once, or for any other reason. For a secure JDK configuration, it is +# important to review OS write permissions assigned to any file included. +# +# Examples: +# 1) include ${java.home}/conf/security/extra.security +# 2) include extra.security +# 3) include ${java.home}/conf/security/profile${SecurityProfile}.security +# # In this file, various security properties are set for use by # java.security classes. This is where users can statically register diff --git a/src/java.base/share/native/libjli/emessages.h b/src/java.base/share/native/libjli/emessages.h index c74fae7a77b36..342b116bfc70c 100644 --- a/src/java.base/share/native/libjli/emessages.h +++ b/src/java.base/share/native/libjli/emessages.h @@ -103,9 +103,6 @@ #define JRE_ERROR12 "Error: Exec of %s failed" #define JRE_ERROR13 "Error: String processing operation failed" -#define SPC_ERROR1 "Error: Specifying an alternate JDK/JRE version is no longer supported.\n The use of the flag '-version:' is no longer valid.\n Please download and execute the appropriate version." -#define SPC_ERROR2 "Error: Specifying an alternate JDK/JRE is no longer supported.\n The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid." - #define DLL_ERROR1 "Error: dl failure on line %d" #define DLL_ERROR2 "Error: failed %s, because %s" #define DLL_ERROR3 "Error: could not find executable %s" diff --git a/src/java.base/share/native/libjli/java.c b/src/java.base/share/native/libjli/java.c index 337ecc846830e..d4e20fb21fe75 100644 --- a/src/java.base/share/native/libjli/java.c +++ b/src/java.base/share/native/libjli/java.c @@ -34,20 +34,15 @@ /* * One job of the launcher is to remove command line options which the - * vm does not understand and will not process. These options include + * vm does not understand and will not process. These options include * options which select which style of vm is run (e.g. -client and - * -server) as well as options which select the data model to use. + * -server). * Additionally, for tools which invoke an underlying vm "-J-foo" * options are turned into "-foo" options to the vm. This option * filtering is handled in a number of places in the launcher, some of * it in machine-dependent code. In this file, the function * CheckJvmType removes vm style options and TranslateApplicationArgs - * removes "-J" prefixes. The CreateExecutionEnvironment function processes - * and removes -d options. On unix, there is a possibility that the running - * data model may not match to the desired data model, in this case an exec is - * required to start the desired model. If the data models match, then - * ParseArguments will remove the -d flags. If the data models do not match - * the CreateExecutionEnviroment will remove the -d flags. + * removes "-J" prefixes. */ @@ -55,11 +50,12 @@ #include "java.h" #include "jni.h" +#include "stdbool.h" /* * A NOTE TO DEVELOPERS: For performance reasons it is important that - * the program image remain relatively small until after SelectVersion - * CreateExecutionEnvironment have finished their possibly recursive + * the program image remain relatively small until after + * CreateExecutionEnvironment has finished its possibly recursive * processing. Watch everything, but resist all temptations to use Java * interfaces. */ @@ -88,10 +84,10 @@ static jboolean _wc_enabled = JNI_FALSE; static jboolean dumpSharedSpaces = JNI_FALSE; /* -Xshare:dump */ /* - * Entries for splash screen environment variables. - * putenv is performed in SelectVersion. We need - * them in memory until UnsetEnv, so they are made static - * global instead of auto local. + * Values that will be stored into splash screen environment variables. + * putenv is performed to set _JAVA_SPLASH_FILE and _JAVA_SPLASH_JAR + * with these values. We need them in memory until UnsetEnv in + * ShowSplashScreen, so they are made static global instead of auto local. */ static char* splash_file_entry = NULL; static char* splash_jar_entry = NULL; @@ -110,19 +106,18 @@ static jboolean IsJavaArgs(); static void SetJavaLauncherProp(); static void SetClassPath(const char *s); static void SetMainModule(const char *s); -static void SelectVersion(int argc, char **argv, char **main_class); static jboolean ParseArguments(int *pargc, char ***pargv, int *pmode, char **pwhat, - int *pret, const char *jrepath); + int *pret); static jboolean InitializeJVM(JavaVM **pvm, JNIEnv **penv, InvocationFunctions *ifn); static jstring NewPlatformString(JNIEnv *env, char *s); static jclass LoadMainClass(JNIEnv *env, int mode, char *name); +static void SetupSplashScreenEnvVars(const char *splash_file_path, char *jar_path); static jclass GetApplicationClass(JNIEnv *env); static void TranslateApplicationArgs(int jargc, const char **jargv, int *pargc, char ***pargv); static jboolean AddApplicationOptions(int cpathc, const char **cpathv); -static void SetApplicationClassPath(const char**); static void PrintJavaVersion(JNIEnv *env); static void PrintUsage(JNIEnv* env, jboolean doXUsage); @@ -130,9 +125,6 @@ static void ShowSettings(JNIEnv* env, char *optString); static void ShowResolvedModules(JNIEnv* env); static void ListModules(JNIEnv* env); static void DescribeModule(JNIEnv* env, char* optString); -static jboolean ValidateModules(JNIEnv* env); - -static void SetPaths(int argc, char **argv); static void DumpState(); @@ -240,7 +232,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ { int mode = LM_UNKNOWN; char *what = NULL; - char *main_class = NULL; int ret; InvocationFunctions ifn; jlong start = 0, end = 0; @@ -257,6 +248,10 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ InitLauncher(javaw); DumpState(); if (JLI_IsTraceLauncher()) { + char *env_in; + if ((env_in = getenv(MAIN_CLASS_ENV_ENTRY)) != NULL) { + printf("Launched through Multiple JRE (mJRE) support\n"); + } int i; printf("Java args:\n"); for (i = 0; i < jargc ; i++) { @@ -269,18 +264,6 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ AddOption("-Dsun.java.launcher.diag=true", NULL); } - /* - * SelectVersion() has several responsibilities: - * - * 1) Disallow specification of another JRE. With 1.9, another - * version of the JRE cannot be invoked. - * 2) Allow for a JRE version to invoke JDK 1.9 or later. Since - * all mJRE directives have been stripped from the request but - * the pre 1.9 JRE [ 1.6 thru 1.8 ], it is as if 1.9+ has been - * invoked from the command line. - */ - SelectVersion(argc, argv, &main_class); - CreateExecutionEnvironment(&argc, &argv, jrepath, sizeof(jrepath), jvmpath, sizeof(jvmpath), @@ -323,7 +306,7 @@ JLI_Launch(int argc, char ** argv, /* main argc, argv */ /* Parse command line options; if the return value of * ParseArguments is false, the program should exit. */ - if (!ParseArguments(&argc, &argv, &mode, &what, &ret, jrepath)) { + if (!ParseArguments(&argc, &argv, &mode, &what, &ret)) { return(ret); } @@ -1078,167 +1061,6 @@ SetMainModule(const char *s) AddOption(def, NULL); } -/* - * The SelectVersion() routine ensures that an appropriate version of - * the JRE is running. The specification for the appropriate version - * is obtained from either the manifest of a jar file (preferred) or - * from command line options. - * The routine also parses splash screen command line options and - * passes on their values in private environment variables. - */ -static void -SelectVersion(int argc, char **argv, char **main_class) -{ - char *arg; - char *operand; - int jarflag = 0; - int headlessflag = 0; - manifest_info info; - char *splash_file_name = NULL; - char *splash_jar_name = NULL; - char *env_in; - int res; - jboolean has_arg; - - /* - * If the version has already been selected, set *main_class - * with the value passed through the environment (if any) and - * simply return. - */ - - /* - * This environmental variable can be set by mJRE capable JREs - * [ 1.5 thru 1.8 ]. All other aspects of mJRE processing have been - * stripped by those JREs. This environmental variable allows 1.9+ - * JREs to be started by these mJRE capable JREs. - * Note that mJRE directives in the jar manifest file would have been - * ignored for a JRE started by another JRE... - * .. skipped for JRE 1.5 and beyond. - * .. not even checked for pre 1.5. - */ - if ((env_in = getenv(ENV_ENTRY)) != NULL) { - if (*env_in != '\0') - *main_class = JLI_StringDup(env_in); - return; - } - - /* - * Scan through the arguments for options relevant to multiple JRE - * support. Multiple JRE support existed in JRE versions 1.5 thru 1.8. - * - * This capability is no longer available with JRE versions 1.9 and later. - * These command line options are reported as errors. - */ - - argc--; - argv++; - while (argc > 0 && *(arg = *argv) == '-') { - has_arg = IsOptionWithArgument(argc, argv); - if (JLI_StrCCmp(arg, "-version:") == 0) { - JLI_ReportErrorMessage(SPC_ERROR1); - } else if (JLI_StrCmp(arg, "-jre-restrict-search") == 0) { - JLI_ReportErrorMessage(SPC_ERROR2); - } else if (JLI_StrCmp(arg, "-jre-no-restrict-search") == 0) { - JLI_ReportErrorMessage(SPC_ERROR2); - } else { - if (JLI_StrCmp(arg, "-jar") == 0) - jarflag = 1; - if (IsWhiteSpaceOption(arg)) { - if (has_arg) { - argc--; - argv++; - arg = *argv; - } - } - - /* - * Checking for headless toolkit option in the some way as AWT does: - * "true" means true and any other value means false - */ - if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) { - headlessflag = 1; - } else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) { - headlessflag = 0; - } else if (JLI_StrCCmp(arg, "-splash:") == 0) { - splash_file_name = arg+8; - } - } - argc--; - argv++; - } - if (argc <= 0) { /* No operand? Possibly legit with -[full]version */ - operand = NULL; - } else { - argc--; - operand = *argv++; - } - - /* - * If there is a jar file, read the manifest. If the jarfile can't be - * read, the manifest can't be read from the jar file, or the manifest - * is corrupt, issue the appropriate error messages and exit. - * - * Even if there isn't a jar file, construct a manifest_info structure - * containing the command line information. It's a convenient way to carry - * this data around. - */ - if (jarflag && operand) { - if ((res = JLI_ParseManifest(operand, &info)) != 0) { - if (res == -1) - JLI_ReportErrorMessage(JAR_ERROR2, operand); - else - JLI_ReportErrorMessage(JAR_ERROR3, operand); - exit(1); - } - - /* - * Command line splash screen option should have precedence - * over the manifest, so the manifest data is used only if - * splash_file_name has not been initialized above during command - * line parsing - */ - if (!headlessflag && !splash_file_name && info.splashscreen_image_file_name) { - splash_file_name = info.splashscreen_image_file_name; - splash_jar_name = operand; - } - } else { - info.manifest_version = NULL; - info.main_class = NULL; - info.jre_version = NULL; - info.jre_restrict_search = 0; - } - - /* - * Passing on splash screen info in environment variables - */ - if (splash_file_name && !headlessflag) { - splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=")+JLI_StrLen(splash_file_name)+1); - JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); - JLI_StrCat(splash_file_entry, splash_file_name); - putenv(splash_file_entry); - } - if (splash_jar_name && !headlessflag) { - splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=")+JLI_StrLen(splash_jar_name)+1); - JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); - JLI_StrCat(splash_jar_entry, splash_jar_name); - putenv(splash_jar_entry); - } - - - /* - * "Valid" returns (other than unrecoverable errors) follow. Set - * main_class as a side-effect of this routine. - */ - if (info.main_class != NULL) - *main_class = JLI_StringDup(info.main_class); - - if (info.jre_version == NULL) { - JLI_FreeManifest(); - return; - } - -} - /* * Test if the current argv is an option, i.e. with a leading `-` * and followed with an argument without a leading `-`. @@ -1325,12 +1147,14 @@ GetOpt(int *pargc, char ***pargv, char **poption, char **pvalue) { static jboolean ParseArguments(int *pargc, char ***pargv, int *pmode, char **pwhat, - int *pret, const char *jrepath) + int *pret) { int argc = *pargc; char **argv = *pargv; int mode = LM_UNKNOWN; char *arg = NULL; + bool headless = false; + char *splash_file_path = NULL; // value of "-splash:" option *pret = 0; @@ -1492,7 +1316,7 @@ ParseArguments(int *pargc, char ***pargv, snprintf(tmp, tmpSize, "-X%s", arg + 1); /* skip '-' */ AddOption(tmp, NULL); } else if (JLI_StrCCmp(arg, "-splash:") == 0) { - ; /* Ignore machine independent options already handled */ + splash_file_path = arg + 8; } else if (JLI_StrCmp(arg, "--disable-@files") == 0) { ; /* Ignore --disable-@files option already handled */ } else if (ProcessPlatformOption(arg)) { @@ -1501,6 +1325,14 @@ ParseArguments(int *pargc, char ***pargv, /* java.class.path set on the command line */ if (JLI_StrCCmp(arg, "-Djava.class.path=") == 0) { _have_classpath = JNI_TRUE; + } else if (JLI_StrCmp(arg, "-Djava.awt.headless=true") == 0) { + /* + * Checking for headless toolkit option in the same way as AWT does: + * "true" means true and any other value means false + */ + headless = true; + } else if (JLI_StrCCmp(arg, "-Djava.awt.headless=") == 0) { + headless = false; } AddOption(arg, NULL); } @@ -1551,9 +1383,82 @@ ParseArguments(int *pargc, char ***pargv, *pmode = mode; + if (!headless) { + char *jar_path = NULL; + if (mode == LM_JAR) { + jar_path = *pwhat; + } + // Not in headless mode. We now set a couple of env variables that + // will be used later by ShowSplashScreen(). + SetupSplashScreenEnvVars(splash_file_path, jar_path); + } + return JNI_TRUE; } +/* + * Sets the relevant environment variables that are subsequently used by + * the ShowSplashScreen() function. The splash_file_path and jar_path parameters + * are used to determine which environment variables to set. + * The splash_file_path is the value that was provided to the "-splash:" option + * when launching java. It may be null, which implies the "-splash:" option wasn't used. + * The jar_path is the value that was provided to the "-jar" option when launching java. + * It too may be null, which implies the "-jar" option wasn't used. + */ +static void +SetupSplashScreenEnvVars(const char *splash_file_path, char *jar_path) { + // Command line specified "-splash:" takes priority over manifest one. + if (splash_file_path) { + // We set up the splash file name as a env variable which then gets + // used when showing the splash screen in ShowSplashScreen(). + + // create the string of the form _JAVA_SPLASH_FILE= + splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=") + + JLI_StrLen(splash_file_path) + 1); + JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); + JLI_StrCat(splash_file_entry, splash_file_path); + putenv(splash_file_entry); + return; + } + if (!jar_path) { + // no jar to look into for "SplashScreen-Image" manifest attribute + return; + } + // parse the jar's manifest to find any "SplashScreen-Image" + int res = 0; + manifest_info info; + if ((res = JLI_ParseManifest(jar_path, &info)) != 0) { + JLI_FreeManifest(); // cleanup any manifest structure + if (res == -1) { + JLI_ReportErrorMessage(JAR_ERROR2, jar_path); + } else { + JLI_ReportErrorMessage(JAR_ERROR3, jar_path); + } + exit(1); + } + if (!info.splashscreen_image_file_name) { + JLI_FreeManifest(); // cleanup the manifest structure + // no "SplashScreen-Image" in jar's manifest + return; + } + // The jar's manifest had a "Splashscreen-Image" specified. We set up the jar entry name + // and the jar file name as env variables which then get used when showing the splash screen + // in ShowSplashScreen(). + + // create the string of the form _JAVA_SPLASH_FILE= + splash_file_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_FILE_ENV_ENTRY "=") + + JLI_StrLen(info.splashscreen_image_file_name) + 1); + JLI_StrCpy(splash_file_entry, SPLASH_FILE_ENV_ENTRY "="); + JLI_StrCat(splash_file_entry, info.splashscreen_image_file_name); + putenv(splash_file_entry); + // create the string of the form _JAVA_SPLASH_JAR= + splash_jar_entry = JLI_MemAlloc(JLI_StrLen(SPLASH_JAR_ENV_ENTRY "=") + JLI_StrLen(jar_path) + 1); + JLI_StrCpy(splash_jar_entry, SPLASH_JAR_ENV_ENTRY "="); + JLI_StrCat(splash_jar_entry, jar_path); + putenv(splash_jar_entry); + JLI_FreeManifest(); // cleanup the manifest structure +} + /* * Initializes the Java Virtual Machine. Also frees options array when * finished. @@ -2340,7 +2245,7 @@ ShowSplashScreen() * Done with all command line processing and potential re-execs so * clean up the environment. */ - (void)UnsetEnv(ENV_ENTRY); + (void)UnsetEnv(MAIN_CLASS_ENV_ENTRY); (void)UnsetEnv(SPLASH_FILE_ENV_ENTRY); (void)UnsetEnv(SPLASH_JAR_ENV_ENTRY); diff --git a/src/java.base/share/native/libjli/java.h b/src/java.base/share/native/libjli/java.h index f768b58a00150..ce5224a7da346 100644 --- a/src/java.base/share/native/libjli/java.h +++ b/src/java.base/share/native/libjli/java.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -48,26 +48,20 @@ # define MB (1024UL * KB) # define GB (1024UL * MB) -#define CURRENT_DATA_MODEL (CHAR_BIT * sizeof(void*)) - /* - * The following environment variable is used to influence the behavior - * of the jre exec'd through the SelectVersion routine. The command line - * options which specify the version are not passed to the exec'd version, - * because that jre may be an older version which wouldn't recognize them. - * This environment variable is known to this (and later) version and serves - * to suppress the version selection code. This is not only for efficiency, - * but also for correctness, since any command line options have been - * removed which would cause any value found in the manifest to be used. - * This would be incorrect because the command line options are defined - * to take precedence. - * - * The value associated with this environment variable is the MainClass - * name from within the executable jar file (if any). This is strictly a - * performance enhancement to avoid re-reading the jar file manifest. - * + * Older versions of java launcher used to support JRE version selection - specifically, + * the java launcher in JDK 1.8 can be used to launch a java application using a different + * java runtime (older, newer or same version JRE installed at a different location) than + * the one the launcher belongs to. + * That support was discontinued starting JDK 9. However, the JDK 8 launcher can still + * be started with JRE version selection options to launch Java runtimes greater than JDK 8. + * In such cases, the JDK 8 launcher when exec()ing the JDK N launcher, will set and propagate + * the _JAVA_VERSION_SET environment variable. The value of this environment variable is the + * Main-Class name from within the executable jar file (if any). + * The java launcher in the current version of the JDK doesn't use this environment variable + * in any way other than merely using it in debug logging. */ -#define ENV_ENTRY "_JAVA_VERSION_SET" +#define MAIN_CLASS_ENV_ENTRY "_JAVA_VERSION_SET" #define SPLASH_FILE_ENV_ENTRY "_JAVA_SPLASH_FILE" #define SPLASH_JAR_ENV_ENTRY "_JAVA_SPLASH_JAR" @@ -107,17 +101,12 @@ JLI_Launch(int argc, char ** argv, /* main argc, argc */ jboolean LoadJavaVM(const char *jvmpath, InvocationFunctions *ifn); -void -GetXUsagePath(char *buf, jint bufsize); - jboolean GetApplicationHome(char *buf, jint bufsize); jboolean GetApplicationHomeFromDll(char *buf, jint bufsize); -#define GetArch() GetArchPath(CURRENT_DATA_MODEL) - /* * Different platforms will implement this, here * pargc is a pointer to the original argc, @@ -153,7 +142,6 @@ void JLI_ShowMessage(const char * message, ...); */ JNIEXPORT void JNICALL JLI_ReportExceptionDescription(JNIEnv * env); -void PrintMachineDependentOptions(); /* * Block current thread and continue execution in new thread. diff --git a/src/java.base/share/native/libjli/manifest_info.h b/src/java.base/share/native/libjli/manifest_info.h index ce18d27ebdeed..b3596f43e8236 100644 --- a/src/java.base/share/native/libjli/manifest_info.h +++ b/src/java.base/share/native/libjli/manifest_info.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -167,10 +167,6 @@ typedef struct zentry { /* Zip file entry */ * Java launcher). */ typedef struct manifest_info { /* Interesting fields from the Manifest */ - char *manifest_version; /* Manifest-Version string */ - char *main_class; /* Main-Class entry */ - char *jre_version; /* Appropriate J2SE release spec */ - char jre_restrict_search; /* Restricted JRE search */ char *splashscreen_image_file_name; /* splashscreen image file */ } manifest_info; diff --git a/src/java.base/share/native/libjli/parse_manifest.c b/src/java.base/share/native/libjli/parse_manifest.c index c351ae8abc1dc..274825a4af5dc 100644 --- a/src/java.base/share/native/libjli/parse_manifest.c +++ b/src/java.base/share/native/libjli/parse_manifest.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -594,10 +594,6 @@ JLI_ParseManifest(char *jarfile, manifest_info *info) )) == -1) { return (-1); } - info->manifest_version = NULL; - info->main_class = NULL; - info->jre_version = NULL; - info->jre_restrict_search = 0; info->splashscreen_image_file_name = NULL; if ((rc = find_file(fd, &entry, manifest_name)) != 0) { close(fd); @@ -610,17 +606,7 @@ JLI_ParseManifest(char *jarfile, manifest_info *info) } lp = manifest; while ((rc = parse_nv_pair(&lp, &name, &value)) > 0) { - if (JLI_StrCaseCmp(name, "Manifest-Version") == 0) { - info->manifest_version = value; - } else if (JLI_StrCaseCmp(name, "Main-Class") == 0) { - info->main_class = value; - } else if (JLI_StrCaseCmp(name, "JRE-Version") == 0) { - /* - * Manifest specification overridden by command line option - * so we will silently override there with no specification. - */ - info->jre_version = 0; - } else if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) { + if (JLI_StrCaseCmp(name, "Splashscreen-Image") == 0) { info->splashscreen_image_file_name = value; } } diff --git a/src/java.base/unix/native/libjli/java_md.c b/src/java.base/unix/native/libjli/java_md.c index 2a1a4e7795a2e..7f2f5638a6b83 100644 --- a/src/java.base/unix/native/libjli/java_md.c +++ b/src/java.base/unix/native/libjli/java_md.c @@ -52,102 +52,86 @@ #endif /* - * Flowchart of launcher execs and options processing on unix + * Following is the high level flow of the launcher + * code residing in the common java.c and this + * unix specific java_md file: * - * The selection of the proper vm shared library to open depends on - * several classes of command line options, including vm "flavor" - * options (-client, -server). - * The vm selection options are not passed to the running - * virtual machine; they must be screened out by the launcher. + * - JLI_Launch function, which is the entry point + * to the launcher, calls CreateExecutionEnvironment. * - * The version specification (if any) is processed first by the - * platform independent routine SelectVersion. This may result in - * the exec of the specified launcher version. + * - CreateExecutionEnvironment does the following + * (not necessarily in this order): + * - determines the relevant JVM type that + * needs to be ultimately created + * - determines the path and asserts the presence + * of libjava and relevant libjvm library + * - removes any JVM selection options from the + * arguments that were passed to the launcher * - * Previously the launcher modified the LD_LIBRARY_PATH appropriately for the - * desired data model path, regardless if data models matched or not. The - * launcher subsequently exec'ed the desired executable, in order to make the - * LD_LIBRARY_PATH path available, for the runtime linker. + * - CreateExecutionEnvironment then determines (by calling + * RequiresSetenv function) if LD_LIBRARY_PATH environment + * variable needs to be set/updated. + * - If LD_LIBRARY_PATH needs to be set/updated, + * then CreateExecutionEnvironment exec()s + * the current process with the appropriate value + * for LD_LIBRARY_PATH. + * - Else if LD_LIBRARY_PATH need not be set or + * updated, then CreateExecutionEnvironment + * returns back. * - * Now, in most cases,the launcher will dlopen the target libjvm.so. All - * required libraries are loaded by the runtime linker, using the - * $RPATH/$ORIGIN baked into the shared libraries at compile time. Therefore, - * in most cases, the launcher will only exec, if the data models are - * mismatched, and will not set any environment variables, regardless of the - * data models. + * - If CreateExecutionEnvironment exec()ed the process + * in the previous step, then the code control for the + * process will again start from the process' entry + * point and JLI_Launch is thus re-invoked and the + * same above sequence of code flow repeats again. + * During this "recursive" call into CreateExecutionEnvironment, + * the implementation of the check for LD_LIBRARY_PATH + * will realize that no further exec() is required and + * the control will return back from CreateExecutionEnvironment. * - * However, if the environment contains a LD_LIBRARY_PATH, this will cause the - * launcher to inspect the LD_LIBRARY_PATH. The launcher will check - * a. if the LD_LIBRARY_PATH's first component is the path to the desired - * libjvm.so - * b. if any other libjvm.so is found in any of the paths. - * If case b is true, then the launcher will set the LD_LIBRARY_PATH to the - * desired JRE and reexec, in order to propagate the environment. + * - The control returns back from CreateExecutionEnvironment + * to JLI_Launch. * - * Main - * (incoming argv) - * | - * \|/ - * CreateExecutionEnvironment - * (determines desired data model) - * | - * | - * \|/ - * Have Desired Model ? --> NO --> Exit(with error) - * | - * | - * \|/ - * YES - * | - * | - * \|/ - * CheckJvmType - * (removes -client, -server, etc.) - * | - * | - * \|/ - * TranslateDashJArgs... - * (Prepare to pass args to vm) - * | - * | - * \|/ - * ParseArguments - * | - * | - * \|/ - * RequiresSetenv - * Is LD_LIBRARY_PATH - * and friends set ? --> NO --> Continue - * YES - * | - * | - * \|/ - * Path is desired JRE ? YES --> Continue - * NO - * | - * | - * \|/ - * Paths have well known - * jvm paths ? --> NO --> Error/Exit - * YES - * | - * | - * \|/ - * Does libjvm.so exist - * in any of them ? --> NO --> Continue - * YES - * | - * | - * \|/ - * Set the LD_LIBRARY_PATH - * | - * | - * \|/ - * Re-exec - * | - * | - * \|/ - * Main + * - JLI_Launch then invokes LoadJavaVM which dlopen()s + * the JVM library and asserts the presence of + * JNI Invocation Functions "JNI_CreateJavaVM", + * "JNI_GetDefaultJavaVMInitArgs" and + * "JNI_GetCreatedJavaVMs" in that library. It then + * sets internal function pointers in the launcher to + * point to those functions. + * + * - JLI_Launch then translates any -J options by + * invoking TranslateApplicationArgs. + * + * - JLI_Launch then invokes ParseArguments to + * parse/process the launcher arguments. + * + * - JLI_Launch then ultimately calls JVMInit. + * + * - JVMInit invokes ShowSplashScreen which displays + * a splash screen for the application, if applicable. + * + * - JVMInit then creates a new thread (T2), in the + * current process, and invokes JavaMain function + * in that new thread. The current thread (T1) then + * waits for the newly launched thread (T2) to complete. + * + * - JavaMain function, in thread T2, before launching + * the application, invokes PostJVMInit. + * + * - PostJVMInit is a no-op and returns back. + * + * - Control then returns back from PostJVMInit into JavaMain, + * which then loads the application's main class and invokes + * the relevant main() Java method. + * + * - JavaMain, in thread T2, then returns back an integer + * result and thread T2 execution ends here. + * + * - The thread T1 in JVMInit, which is waiting on T2 to + * complete, receives the integer result and then propagates + * it as a return value all the way out of the + * JLI_Launch function. */ /* Store the name of the executable once computed */ @@ -221,13 +205,12 @@ ContainsLibJVM(const char *env) { } /* - * Test whether the environment variable needs to be set, see flowchart. + * Test whether the LD_LIBRARY_PATH environment variable needs to be set. */ static jboolean RequiresSetenv(const char *jvmpath) { char jpath[PATH_MAX + 1]; char *llp; - char *dmllp = NULL; char *p; /* a utility pointer */ #ifdef MUSL_LIBC @@ -245,7 +228,7 @@ RequiresSetenv(const char *jvmpath) { llp = getenv("LD_LIBRARY_PATH"); /* no environment variable is a good environment variable */ - if (llp == NULL && dmllp == NULL) { + if (llp == NULL) { return JNI_FALSE; } #ifdef __linux @@ -284,9 +267,6 @@ RequiresSetenv(const char *jvmpath) { if (llp != NULL && ContainsLibJVM(llp)) { return JNI_TRUE; } - if (dmllp != NULL && ContainsLibJVM(dmllp)) { - return JNI_TRUE; - } return JNI_FALSE; } #endif /* SETENV_REQUIRED */ diff --git a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java index 4e844df03f8a0..4ccd1d702bd1b 100644 --- a/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java +++ b/src/java.base/windows/classes/sun/nio/fs/WindowsLinkSupport.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -86,7 +86,7 @@ static String readLink(WindowsPath path) throws IOException { x.rethrowAsIOException(path); } try { - return readLinkImpl(handle); + return readLinkImpl(path, handle); } finally { CloseHandle(handle); } @@ -297,16 +297,18 @@ static String getRealPath(WindowsPath input, boolean resolveLinks) * Returns target of a symbolic link given the handle of an open file * (that should be a link). */ - private static String readLinkImpl(long handle) throws IOException { + private static String readLinkImpl(WindowsPath path, long handle) + throws IOException + { int size = MAXIMUM_REPARSE_DATA_BUFFER_SIZE; try (NativeBuffer buffer = NativeBuffers.getNativeBuffer(size)) { try { DeviceIoControlGetReparsePoint(handle, buffer.address(), size); } catch (WindowsException x) { - // FIXME: exception doesn't have file name + String pathname = path.getPathForExceptionMessage(); if (x.lastError() == ERROR_NOT_A_REPARSE_POINT) - throw new NotLinkException(null, null, x.errorString()); - x.rethrowAsIOException((String)null); + throw new NotLinkException(pathname, null, x.errorString()); + x.rethrowAsIOException(pathname + ": " + x.errorString()); } /* @@ -342,8 +344,8 @@ private static String readLinkImpl(long handle) throws IOException { int tag = (int)unsafe.getLong(buffer.address() + OFFSETOF_REPARSETAG); if (tag != IO_REPARSE_TAG_SYMLINK) { - // FIXME: exception doesn't have file name - throw new NotLinkException(null, null, "Reparse point is not a symbolic link"); + String pathname = path.getPathForExceptionMessage(); + throw new NotLinkException(pathname, null, "Reparse point is not a symbolic link"); } // get offset and length of target diff --git a/src/java.base/windows/native/libjava/java_props_md.c b/src/java.base/windows/native/libjava/java_props_md.c index 5eefb6a9fc9e8..d26d6df1affad 100644 --- a/src/java.base/windows/native/libjava/java_props_md.c +++ b/src/java.base/windows/native/libjava/java_props_md.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -233,9 +233,6 @@ cpu_isalist(void) SYSTEM_INFO info; GetSystemInfo(&info); switch (info.wProcessorArchitecture) { -#ifdef PROCESSOR_ARCHITECTURE_IA64 - case PROCESSOR_ARCHITECTURE_IA64: return "ia64"; -#endif #ifdef PROCESSOR_ARCHITECTURE_AMD64 case PROCESSOR_ARCHITECTURE_AMD64: return "amd64"; #endif @@ -444,6 +441,8 @@ GetJavaProperties(JNIEnv* env) * where (buildNumber > 17762) * Windows Server 2022 10 0 (!VER_NT_WORKSTATION) * where (buildNumber > 20347) + * Windows Server 2025 10 0 (!VER_NT_WORKSTATION) + * where (buildNumber > 26039) * * This mapping will presumably be augmented as new Windows * versions are released. @@ -527,7 +526,10 @@ GetJavaProperties(JNIEnv* env) case 0: /* Windows server 2019 GA 10/2018 build number is 17763 */ /* Windows server 2022 build number is 20348 */ - if (buildNumber > 20347) { + /* Windows server 2025 Preview build is 26040 */ + if (buildNumber > 26039) { + sprops.os_name = "Windows Server 2025"; + } else if (buildNumber > 20347) { sprops.os_name = "Windows Server 2022"; } else if (buildNumber > 17762) { sprops.os_name = "Windows Server 2019"; diff --git a/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java b/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java index 3d65d200c0d1a..108e3789d287f 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/AbstractProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -157,7 +157,7 @@ public SourceVersion getSupportedSourceVersion() { * * @implSpec * Initializes the processor with the processing environment by - * setting the {@code processingEnv} field to the value of the + * setting the {@link #processingEnv} field to the value of the * {@code processingEnv} argument. An {@code * IllegalStateException} will be thrown if this method is called * more than once on the same object. diff --git a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java index 01de039d2c2c8..4be159868fa10 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/Processor.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/Processor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -32,14 +32,15 @@ import javax.lang.model.SourceVersion; /** - * The interface for an annotation processor. - * - *

    Annotation processing happens in a sequence of {@linkplain - * javax.annotation.processing.RoundEnvironment rounds}. On each - * round, a processor may be asked to {@linkplain #process process} a - * subset of the annotations found on the source and class files - * produced by a prior round. The inputs to the first round of - * processing are the initial inputs to a run of the tool; these + * The interface for an {@index "annotation processor"}. + * + *

    Annotation processing happens in a sequence of rounds. + * On each + * {@linkplain RoundEnvironment round}, a processor may be asked to {@linkplain #process process} a + * subset of the annotations found on the + * {@linkplain RoundEnvironment#getRootElements() source and class files + * produced by a prior round}. The inputs to the first round of + * processing are the {@index "initial inputs"} to a run of the tool; these * initial inputs can be regarded as the output of a virtual zeroth * round of processing. If a processor was asked to process on a * given round, it will be asked to process on subsequent rounds, @@ -77,7 +78,7 @@ * protocol being followed, then the processor's behavior is not * defined by this interface specification. * - *

    The tool uses a discovery process to find annotation + *

    The tool uses a {@index "discovery process"} to find annotation * processors and decide whether or not they should be run. By * configuring the tool, the set of potential processors can be * controlled. For example, for a {@link javax.tools.JavaCompiler diff --git a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java index 49e94faf179e4..d0c43d929c8d9 100644 --- a/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java +++ b/src/java.compiler/share/classes/javax/annotation/processing/RoundEnvironment.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -146,7 +146,7 @@ default Set getElementsAnnotatedWithAny(TypeElement... annota * processing. The set of annotation interfaces present in the runtime * context may differ from the set of annotation interfaces present in * the context of annotation processing in a particular - * environmental configuration. If an runtime annotation interface is + * environmental configuration. If a runtime annotation interface is * not present in the annotation processing context, the situation * is not treated as an error and no elements are found for that * annotation interface. @@ -173,7 +173,7 @@ default Set getElementsAnnotatedWithAny(TypeElement... annota * processing. The set of annotation interfaces present in the runtime * context may differ from the set of annotation interfaces present in * the context of annotation processing in a particular - * environmental configuration. If an runtime annotation interface is + * environmental configuration. If a runtime annotation interface is * not present in the annotation processing context, the situation * is not treated as an error and no elements are found for that * annotation interface. diff --git a/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java b/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java index 10363b5a618d1..2bb275a046b09 100644 --- a/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java +++ b/src/java.compiler/share/classes/javax/lang/model/AnnotatedConstruct.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2013, 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 @@ -41,20 +41,20 @@ * * As defined by The Java Language Specification * section {@jls 9.7.4}, an annotation on an element is a - * declaration annotation and an annotation on a type is a - * type annotation. + * {@index "declaration annotation"} and an annotation on a type is a + * {@index "type annotation"}. * * The terms directly present, present, - * indirectly present, and associated are used + * indirectly present, and associated are used * throughout this interface to describe precisely which annotations, * either declaration annotations or type annotations, are returned by * the methods in this interface. * *

    In the definitions below, an annotation A has an * annotation interface AI. If AI is a repeatable annotation - * interface, the type of the containing annotation is AIC. + * interface, the type of the container annotation is AIC. * - *

    Annotation A is directly present on a construct + *

    Annotation A is {@index "directly present"} on a construct * C if either: * *

      @@ -78,7 +78,7 @@ * Specification (JLS {@jls 8.10.1}). * * If there are multiple annotations of type AI present on - * C, then if AI is repeatable annotation interface, an + * C, then if AI is a repeatable annotation interface, an * annotation of type AIC is {@linkplain javax.lang.model.util.Elements#getOrigin(AnnotatedConstruct, AnnotationMirror) implicitly declared} on C. *
    • A representation of A appears in the executable output * for C, such as the {@code RuntimeVisibleAnnotations} (JVMS {@jvms 4.7.16}) or @@ -87,7 +87,7 @@ * *
    * - *

    An annotation A is present on a + *

    An annotation A is {@index "present"} on a * construct C if either: *

      * @@ -99,7 +99,7 @@ * *
    * - * An annotation A is indirectly present on a construct + * An annotation A is {@index "indirectly present"} on a construct * C if both: * *
      @@ -114,7 +114,7 @@ * *
    * - * An annotation A is associated with a construct + * An annotation A is {@index "associated"} with a construct * C if either: * *
      @@ -189,10 +189,11 @@ public interface AnnotatedConstruct { A getAnnotation(Class annotationType); /** - * Returns annotations that are associated with this construct. + * Returns annotations of the specified type that are associated + * with this construct. * - * If there are no annotations associated with this construct, the - * return value is an array of length 0. + * If there are no annotations of the specified type associated with this + * construct, the return value is an array of length 0. * * The order of annotations which are directly or indirectly * present on a construct C is computed as if indirectly present diff --git a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java index 4e32f0cdcd88e..231a5e34c62b7 100644 --- a/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java +++ b/src/java.compiler/share/classes/javax/lang/model/SourceVersion.java @@ -70,8 +70,14 @@ public enum SourceVersion { * 21: pattern matching for switch and record patterns (string * templates in preview, unnamed patterns and variables in * preview, unnamed classes and instance main methods in preview) - * 22: Unnamed Variables & Patterns (Statements before super(...) - * in Preview) + * 22: unnamed variables & patterns (statements before super(...) + * in preview, string templates in second preview, implicitly + * declared classes and instance main methods in second preview) + * 23: no changes (primitive Types in Patterns, instanceof, and + * switch in preview, module Import Declarations in preview, + * implicitly declared classes and instance main in third + * preview, flexible constructor bodies in second preview) + * 24: tbd */ /** @@ -202,7 +208,7 @@ public enum SourceVersion { * @see * JEP 213: Milling Project Coin */ - RELEASE_9, + RELEASE_9, /** * The version introduced by the Java Platform, Standard Edition @@ -470,7 +476,7 @@ private static SourceVersion getLatestSupported() { * * @apiNote This method is included alongside {@link latest} to * allow identification of situations where the language model API - * is running on a platform version different than the latest + * is running on a platform version different from the latest * version modeled by the API. One way that sort of situation can * occur is if an IDE or similar tool is using the API to model * source version N while running on platform version @@ -496,8 +502,7 @@ public static SourceVersion latestSupported() { * followed only by characters for which {@link * Character#isJavaIdentifierPart(int)} returns {@code true}. * This pattern matches regular identifiers, keywords, contextual - * keywords, and the literals {@code "true"}, - * {@code "false"}, {@code "null"}. + * keywords, boolean literals, and the null literal. * * The method returns {@code false} for all other strings. * @@ -590,14 +595,14 @@ public static boolean isName(CharSequence name, SourceVersion version) { } /** - * Returns whether or not {@code s} is a keyword, boolean literal, - * or null literal in the latest source version. + * Returns whether or not {@code s} is a keyword, a boolean literal, + * or the null literal in the latest source version. * This method returns {@code false} for contextual * keywords. * * @param s the string to check - * @return {@code true} if {@code s} is a keyword, or boolean - * literal, or null literal, {@code false} otherwise. + * @return {@code true} if {@code s} is a keyword, a boolean + * literal, or the null literal, {@code false} otherwise. * @jls 3.9 Keywords * @jls 3.10.3 Boolean Literals * @jls 3.10.8 The Null Literal @@ -607,15 +612,15 @@ public static boolean isKeyword(CharSequence s) { } /** - * Returns whether or not {@code s} is a keyword, boolean literal, - * or null literal in the given source version. + * Returns whether or not {@code s} is a keyword, a boolean literal, + * or the null literal in the given source version. * This method returns {@code false} for contextual * keywords. * * @param s the string to check * @param version the version to use - * @return {@code true} if {@code s} is a keyword, or boolean - * literal, or null literal, {@code false} otherwise. + * @return {@code true} if {@code s} is a keyword, a boolean + * literal, or the null literal, {@code false} otherwise. * @jls 3.9 Keywords * @jls 3.10.3 Boolean Literals * @jls 3.10.8 The Null Literal diff --git a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java index 908d171e9c7f8..2d92504edb68f 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/AnnotationMirror.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -47,7 +47,7 @@ public interface AnnotationMirror { /** * Returns the values of this annotation's elements. - * This is returned in the form of a map that associates elements + * These are returned in the form of a map that associates elements * with their corresponding values. * Only those elements with values explicitly present in the * annotation are included, not those that are implicitly assuming diff --git a/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java b/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java index 8bff37483947c..18923463248e2 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/ExecutableElement.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,7 +34,7 @@ * elements. * Annotation interface elements are methods restricted to have no * formal parameters, no type parameters, and no {@code throws} - * clause, among other restrictions; see JLS {@jls 9.6.1} for details + * clause, among other restrictions; see JLS {@jls 9.6.1} for details. * * @see ExecutableType * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java index 138f093be2f57..1faae30df5723 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/NestingKind.java @@ -26,7 +26,7 @@ package javax.lang.model.element; /** - * The nesting kind of a type element. + * The nesting kind of a type element. * Type elements come in four varieties: * top-level, member, local, and anonymous. * Nesting kind is a non-standard term used here to denote this @@ -107,7 +107,7 @@ public enum NestingKind { /** * Does this constant correspond to a nested type element? - * A nested type element is any that is not top-level. + * A nested type element is any that is not top-level. * More specifically, an inner type element is any nested type element that * is not {@linkplain Modifier#STATIC static}. * @return whether or not the constant is nested diff --git a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java index 3f34b1799929d..abf95bcefad50 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/TypeElement.java @@ -58,14 +58,14 @@ * javax.lang.model.util.Elements#getFileObjectOf(Element) reference * representation} (either source code or executable output). Multiple * classes and interfaces can share the same reference representation - * backing construct. For example, multiple classes and interface can - * be declared in the same source file, including, but are not limited + * backing construct. For example, multiple classes and interfaces can + * be declared in the same source file, including, but not limited * to: *
        *
      • a {@linkplain NestingKind#TOP_LEVEL top-level} class or * interface and auxiliary classes and interfaces *
      • a top-level class or interface and {@linkplain - * NestingKind#isNested() nested class and interfaces} within it + * NestingKind#isNested() nested classes and interfaces} within it *
      *

      In the context of annotation processing, a type element can * be: diff --git a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java index 56edb89d3e35c..ab4eeb1e747ec 100644 --- a/src/java.compiler/share/classes/javax/lang/model/element/package-info.java +++ b/src/java.compiler/share/classes/javax/lang/model/element/package-info.java @@ -30,7 +30,7 @@ * elements, the declared entities that make up a program. Elements * include classes, interfaces, methods, constructors, and fields. * The interfaces in this package do not model the structure of a - * program inside a method body; for example there is no + * program inside a method body; for example, there is no * representation of a {@code for} loop or {@code try}-{@code finally} * block. Concretely, there is no model of any abstract syntax tree * (AST) structure of a Java program. However, the interfaces can @@ -84,7 +84,7 @@ * javax.lang.model.util.Elements#isBridge(ExecutableElement) * bridge methods} used in implementing covariant returns, are * translation artifacts strictly outside of this model. However, when - * operating on class files, it is helpful be able to operate on such + * operating on class files, it is helpful to be able to operate on such * elements, screening them out when appropriate. * *

      During annotation processing, operating on incomplete or diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java index 2faf3f5ec32b2..5159ac26e3bfa 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Elements.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Elements.java @@ -56,11 +56,11 @@ public interface Elements { *

        *
      • find non-empty packages with the given name returned by * {@link #getPackageElement(ModuleElement, CharSequence)}, - * where the provided ModuleSymbol is any + * where the provided ModuleElement is any * {@linkplain java.lang.module##root-modules root module}, *
      • *
      • if the above yields an empty list, search - * {@link #getAllModuleElements() all modules} for observable + * {@linkplain #getAllModuleElements() all modules} for observable * packages with the given name *
      • *
      @@ -143,11 +143,11 @@ default Set getAllPackageElements(CharSequence name) { *
        *
      • find type elements with the given name returned by * {@link #getTypeElement(ModuleElement, CharSequence)}, - * where the provided ModuleSymbol is any + * where the provided ModuleElement is any * {@linkplain java.lang.module##root-modules root module}, *
      • *
      • if the above yields an empty list, search - * {@link #getAllModuleElements() all modules} for observable + * {@linkplain #getAllModuleElements() all modules} for observable * type elements with the given name *
      • *
      @@ -617,7 +617,7 @@ default ModuleElement getModuleOf(Element e) { /** * Returns all members of a type element, whether inherited or - * declared directly. For a class the result also includes its + * declared directly. For a class, the result also includes its * constructors, but not local or anonymous classes. * * @apiNote Elements of certain kinds can be isolated using @@ -878,10 +878,10 @@ default TypeElement getEnumConstantBody(VariableElement enumConstant) { * accessor. * * @implSpec The default implementation of this method checks if the element - * enclosing the accessor has kind {@link ElementKind#RECORD RECORD} if that is - * the case, then all the record components on the accessor's enclosing element - * are retrieved by invoking {@link ElementFilter#recordComponentsIn(Iterable)}. - * If the accessor of at least one of the record components retrieved happen to + * enclosing the accessor has kind {@link ElementKind#RECORD RECORD}, if that is + * the case, then all the record components of the accessor's enclosing element + * are isolated by invoking {@link ElementFilter#recordComponentsIn(Iterable)}. + * If the accessor of at least one of the record components retrieved happens to * be equal to the accessor passed as a parameter to this method, then that * record component is returned, in any other case {@code null} is returned. * diff --git a/src/java.compiler/share/classes/javax/lang/model/util/Types.java b/src/java.compiler/share/classes/javax/lang/model/util/Types.java index 0cea2734e213c..266d63178ba08 100644 --- a/src/java.compiler/share/classes/javax/lang/model/util/Types.java +++ b/src/java.compiler/share/classes/javax/lang/model/util/Types.java @@ -40,7 +40,7 @@ * ExecutableType Executable types} and the pseudo-types for * {@linkplain TypeKind#PACKAGE packages} and {@linkplain * TypeKind#MODULE modules} are generally out of scope for these - * methods. One or more out of scope arguments will typically result + * methods. One or more out-of-scope arguments will typically result * in a method throwing an {@link IllegalArgumentException}. * *

      Where a method returns a type mirror or a collection of type @@ -165,7 +165,7 @@ public interface Types { * the direct supertypes of a type mirror representing {@code * java.lang.Object}. * - * Annotations on the direct super types are preserved. + * Annotations on the direct supertypes are preserved. * * @param t the type being examined * @return the direct supertypes, or an empty list if none @@ -185,7 +185,7 @@ public interface Types { /** * {@return the class of a boxed value of the primitive type argument} - * That is, boxing conversion is applied. + * That is, boxing conversion is applied. * * @param p the primitive type to be converted * @jls 5.1.7 Boxing Conversion @@ -318,7 +318,7 @@ WildcardType getWildcardType(TypeMirror extendsBound, * Annotations on the type arguments are preserved. * *

      If the containing type is a parameterized type, - * the number of type arguments must equal the + * the number of type arguments must be equal to the * number of {@code typeElem}'s formal type parameters. * If it is not parameterized or if it is {@code null}, this method is * equivalent to {@code getDeclaredType(typeElem, typeArgs)}. @@ -354,7 +354,7 @@ DeclaredType getDeclaredType(DeclaredType containing, /** * {@return a type mirror equivalent to the argument, but with no annotations} * If the type mirror is a composite type, such as an array type - * or a wildcard type, any constitute types, such as the + * or a wildcard type, any constituent types, such as the * component type of an array and the type of the bounds of a * wildcard type, also have no annotations, recursively. * diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java b/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java index 98bb5a650a406..d61198c6aef8b 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -39,7 +39,7 @@ * additional fields and methods. * *

      Unless stated otherwise, references in this class to "this file object" - * should be interpreted as referring indirectly to the {@link #fileObject delegate file object}. + * should be interpreted as referring indirectly to the {@linkplain #fileObject delegate file object}. * * @param the kind of file object forwarded to by this object * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java index 40224abbd509d..9db757f05a242 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -39,7 +39,7 @@ * additional fields and methods. * *

      Unless stated otherwise, references in this class to "this file manager" - * should be interpreted as referring indirectly to the {@link #fileManager delegate file manager}. + * should be interpreted as referring indirectly to the {@linkplain #fileManager delegate file manager}. * * @param the kind of file manager forwarded to by this object * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java index a940b23009d8e..e8db8919750a3 100644 --- a/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java +++ b/src/java.compiler/share/classes/javax/tools/ForwardingJavaFileObject.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -34,7 +34,7 @@ * additional fields and methods. * *

      Unless stated otherwise, references in this class to "this file object" - * should be interpreted as referring indirectly to the {@link #fileObject delegate file object}. + * should be interpreted as referring indirectly to the {@linkplain #fileObject delegate file object}. * * @param the kind of file object forwarded to by this object * @since 1.6 diff --git a/src/java.compiler/share/classes/javax/tools/JavaFileManager.java b/src/java.compiler/share/classes/javax/tools/JavaFileManager.java index 327064b5a5215..da2a3b534acf1 100644 --- a/src/java.compiler/share/classes/javax/tools/JavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/JavaFileManager.java @@ -52,7 +52,7 @@ * *

      Some methods in this interface use class names. Such class * names must be given in the Java Virtual Machine internal form of - * fully qualified class and interface names. For convenience '.' + * fully qualified class and interface names. For convenience, '.' * and '/' are interchangeable. The internal form is defined in * chapter four of * The Java Virtual Machine Specification. @@ -239,7 +239,7 @@ Iterable list(Location location, String inferBinaryName(Location location, JavaFileObject file); /** - * Compares two file objects and return true if they represent the + * Compares two file objects and returns true if they represent the * same underlying object. * * @param a a file object @@ -255,7 +255,7 @@ Iterable list(Location location, /** * Handles one option. If {@code current} is an option to this - * file manager it will consume any arguments to that option from + * file manager, it will consume any arguments to that option from * {@code remaining} and return true, otherwise return false. * * @param current current option diff --git a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java index 769856535acee..277f6d57b0eb5 100644 --- a/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java +++ b/src/java.compiler/share/classes/javax/tools/StandardJavaFileManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2006, 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 @@ -142,7 +142,7 @@ *

    * *

    All implementations of this interface must support Path objects representing - * files in the {@linkplain java.nio.file.FileSystems#getDefault() default file system.} + * files in the {@linkplain java.nio.file.FileSystems#getDefault() default file system}. * It is recommended that implementations should support Path objects from any filesystem.

    * * diff --git a/src/java.compiler/share/classes/javax/tools/ToolProvider.java b/src/java.compiler/share/classes/javax/tools/ToolProvider.java index d05b65b0ffe94..8cdfd63b17ded 100644 --- a/src/java.compiler/share/classes/javax/tools/ToolProvider.java +++ b/src/java.compiler/share/classes/javax/tools/ToolProvider.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -90,8 +90,8 @@ public static DocumentationTool getSystemDocumentationTool() { * @implSpec This implementation always returns {@code null}. * @deprecated This method is subject to removal in a future version of * Java SE. - * Use the {@link java.util.spi.ToolProvider system tool provider} or - * {@link java.util.ServiceLoader service loader} mechanisms to + * Use the {@linkplain java.util.spi.ToolProvider system tool provider} or + * {@linkplain java.util.ServiceLoader service loader} mechanisms to * locate system tools as well as user-installed tools. * @return a class loader, or {@code null} */ diff --git a/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java b/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java index 384a805996289..92f98fdfc992f 100644 --- a/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java +++ b/src/java.desktop/share/classes/javax/swing/SortingFocusTraversalPolicy.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -87,8 +87,8 @@ public class SortingFocusTraversalPolicy private static final SwingContainerOrderFocusTraversalPolicy fitnessTestPolicy = new SwingContainerOrderFocusTraversalPolicy(); - private final int FORWARD_TRAVERSAL = 0; - private final int BACKWARD_TRAVERSAL = 1; + private static final int FORWARD_TRAVERSAL = 0; + private static final int BACKWARD_TRAVERSAL = 1; /* * When true (by default), the legacy merge-sort algo is used to sort an FTP cycle. diff --git a/src/java.desktop/share/legal/giflib.md b/src/java.desktop/share/legal/giflib.md index 8b8fde8706d92..5697dc7ca9ab2 100644 --- a/src/java.desktop/share/legal/giflib.md +++ b/src/java.desktop/share/legal/giflib.md @@ -23,8 +23,13 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +--------------------------------- +The below applies to the following file(s): +giflib/openbsd-reallocarray.c + +Copyright (C) 2008 Otto Moerbeek +SPDX-License-Identifier: MIT -tree/README == Authors == @@ -38,13 +43,4 @@ former maintainer Eric Raymond current as well as long time former maintainer of giflib code -There have been many other contributors; see the attributions in the -version-control history to learn more. - - -tree/openbsd-reallocarray.c - -Copyright (C) 2008 Otto Moerbeek -SPDX-License-Identifier: MIT - ``` diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java index acd79c69bd45f..be311bb3ab84c 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/parser/DocCommentParser.java @@ -286,16 +286,17 @@ protected List content(Phase phase) { int depth = 1; // only used when phase is INLINE int pos = bp; // only used when phase is INLINE + if (textKind == DocTree.Kind.MARKDOWN) { + initMarkdownLine(); + } + loop: while (bp < buflen) { switch (ch) { case '\n', '\r' -> { nextChar(); if (textKind == DocTree.Kind.MARKDOWN) { - markdown.update(); - if (markdown.isIndentedCodeBlock()) { - markdown.skipLine(); - } + initMarkdownLine(); } } @@ -488,6 +489,17 @@ void defaultContentCharacter() { nextChar(); } + void initMarkdownLine() { + if (textStart == -1) { + textStart = bp; + } + markdown.update(); + if (markdown.isIndentedCodeBlock()) { + markdown.skipLine(); + lastNonWhite = bp - 1; // do not include newline or EOF + } + } + private IllegalStateException unknownTextKind(DocTree.Kind textKind) { return new IllegalStateException(textKind.toString()); } diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java index 77f6eefc073eb..9e0767b6e2161 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/DocTreeMaker.java @@ -592,27 +592,33 @@ Pair, List> splitBody(List list) { case TEXT, MARKDOWN -> { var peekedNext = iter.hasNext() ? alist.get(iter.nextIndex()) : null; var content = getContent(dt); - int breakOffset = getSentenceBreak(dt.getKind(), content, peekedNext); - if (breakOffset > 0) { - // the end of sentence is within the current node; - // split it, skipping whitespace in between the two parts - var fsPart = newNode(dt.getKind(), dt.pos, content.substring(0, breakOffset).stripTrailing()); - fs.add(fsPart); - int wsOffset = skipWhiteSpace(content, breakOffset); - if (wsOffset > 0) { - var bodyPart = newNode(dt.getKind(), dt.pos + wsOffset, content.substring(wsOffset)); - body.add(bodyPart); - } - foundFirstSentence = true; - } else if (peekedNext != null && isSentenceBreak(peekedNext, false)) { - // the next node is a sentence break, so this is the end of the first sentence; - // remove trailing spaces - var fsPart = newNode(dt.getKind(), dt.pos, content.stripTrailing()); - fs.add(fsPart); + if (isFirst && dt.getKind() == Kind.MARKDOWN && isIndented(content)) { + // begins with an indented code block (unusual), so no first sentence + body.add(dt); foundFirstSentence = true; } else { - // no sentence break found; keep scanning - fs.add(dt); + int breakOffset = getSentenceBreak(dt.getKind(), content, peekedNext); + if (breakOffset > 0) { + // the end of sentence is within the current node; + // split it, skipping whitespace in between the two parts + var fsPart = newNode(dt.getKind(), dt.pos, content.substring(0, breakOffset).stripTrailing()); + fs.add(fsPart); + int wsOffset = skipWhiteSpace(content, breakOffset); + if (wsOffset > 0) { + var bodyPart = newNode(dt.getKind(), dt.pos + wsOffset, content.substring(wsOffset)); + body.add(bodyPart); + } + foundFirstSentence = true; + } else if (peekedNext != null && isSentenceBreak(peekedNext, false)) { + // the next node is a sentence break, so this is the end of the first sentence; + // remove trailing spaces + var fsPart = newNode(dt.getKind(), dt.pos, content.stripTrailing()); + fs.add(fsPart); + foundFirstSentence = true; + } else { + // no sentence break found; keep scanning + fs.add(dt); + } } } @@ -651,6 +657,11 @@ private String getContent(DCTree dt) { }; } + private static final Pattern INDENT = Pattern.compile(" {4}| {0,3}\t"); + private boolean isIndented(String s) { + return INDENT.matcher(s).lookingAt(); + } + private DCTree newNode(DocTree.Kind kind, int pos, String text) { return switch (kind) { case TEXT -> m.at(pos).newTextTree(text); diff --git a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java index e97d07b1d2bfa..919b2325ef669 100644 --- a/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java +++ b/src/jdk.compiler/share/classes/com/sun/tools/javac/tree/Pretty.java @@ -1467,7 +1467,7 @@ public void visitLiteral(JCLiteral tree) { break; case CHAR: print('\''); - print(Convert.quote(String.valueOf((char)((Number)tree.value).intValue()))); + print(Convert.quote((char)((Number)tree.value).intValue(), true)); print('\''); break; case BOOLEAN: diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedOops.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedOops.java index 056d75199579c..01c9974153392 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedOops.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/oops/CompressedOops.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2000, 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 @@ -64,8 +64,8 @@ private static boolean typeExists(TypeDataBase db, String type) { private static synchronized void initialize(TypeDataBase db) { Type type = db.lookupType("CompressedOops"); - baseField = type.getAddressField("_narrow_oop._base"); - shiftField = type.getCIntegerField("_narrow_oop._shift"); + baseField = type.getAddressField("_base"); + shiftField = type.getCIntegerField("_shift"); } public CompressedOops() { diff --git a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java index 224206ee6fe59..a47a632c286ef 100644 --- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java +++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/ppc64/PPC64Frame.java @@ -345,8 +345,9 @@ private Frame senderForUpcallStub(PPC64RegisterMap map, UpcallStub stub) { //------------------------------------------------------------------------------ // frame::adjust_unextended_sp private void adjustUnextendedSP() { - raw_unextendedSP = getFP(); + // Nothing to do. senderForInterpreterFrame finds the correct unextendedSP. } + private Frame senderForInterpreterFrame(PPC64RegisterMap map) { if (DEBUG) { System.out.println("senderForInterpreterFrame"); diff --git a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java index 9a1fef061e3f4..d25a7c974a5cf 100644 --- a/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java +++ b/src/jdk.internal.vm.ci/share/classes/jdk/vm/ci/hotspot/HotSpotJVMCICompilerConfig.java @@ -104,12 +104,15 @@ static JVMCICompilerFactory getCompilerFactory(HotSpotJVMCIRuntime runtime) { } } if (factory == null) { + String reason; if (Services.IS_IN_NATIVE_IMAGE) { - throw runtime.exitHotSpotWithMessage(1, "JVMCI compiler '%s' not found in JVMCI native library.%n" + + reason = String.format("JVMCI compiler '%s' not found in JVMCI native library.%n" + "Use -XX:-UseJVMCINativeLibrary when specifying a JVMCI compiler available on a class path with %s.%n", compilerName, compPropertyName); + } else { + reason = String.format("JVMCI compiler '%s' specified by %s not found%n", compilerName, compPropertyName); } - throw runtime.exitHotSpotWithMessage(1, "JVMCI compiler '%s' specified by %s not found%n", compilerName, compPropertyName); + factory = new DummyCompilerFactory(reason, runtime); } } } else { diff --git a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css index 1130f14dc35b4..97fcc91eadcfd 100644 --- a/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css +++ b/src/jdk.javadoc/share/classes/jdk/javadoc/internal/doclets/formats/html/resources/stylesheet.css @@ -360,8 +360,11 @@ main { padding:10px 20px; position:relative; } -section[id$=-description] :is(dl, ol, ul, p, div, blockquote, pre):last-child, -section[id$=-description] :is(dl, ol, ul):last-child > :is(li, dd):last-child { +/* Compensate for non-collapsing margins between element description and summary tables */ +div.horizontal-scroll > section[id$=-description] > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +div.horizontal-scroll > section[id$=-description] > :last-child > :is(li, dd):last-child, +section.class-description > div.horizontal-scroll > :is(dl, ol, ul, p, div, blockquote, pre):last-child, +section.class-description > div.horizontal-scroll > :last-child > :is(li, dd):last-child { margin-bottom:4px; } dl.notes > dt { diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java index 3b9336c499d9c..cccbaf14f5399 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/AttributeWriter.java @@ -35,6 +35,7 @@ import java.lang.classfile.attribute.*; import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.attribute.StackMapFrameInfo.*; +import static java.lang.classfile.instruction.CharacterRange.*; /* * A writer for writing Attributes as text. @@ -144,23 +145,23 @@ public void write(Attribute a, CodeAttribute lr) { (e.characterRangeStart() & 0x3ff), (e.characterRangeEnd() >> 10), (e.characterRangeEnd() & 0x3ff))); - if ((e.flags() & CRT_STATEMENT) != 0) + if ((e.flags() & FLAG_STATEMENT) != 0) print(", statement"); - if ((e.flags() & CRT_BLOCK) != 0) + if ((e.flags() & FLAG_BLOCK) != 0) print(", block"); - if ((e.flags() & CRT_ASSIGNMENT) != 0) + if ((e.flags() & FLAG_ASSIGNMENT) != 0) print(", assignment"); - if ((e.flags() & CRT_FLOW_CONTROLLER) != 0) + if ((e.flags() & FLAG_FLOW_CONTROLLER) != 0) print(", flow-controller"); - if ((e.flags() & CRT_FLOW_TARGET) != 0) + if ((e.flags() & FLAG_FLOW_TARGET) != 0) print(", flow-target"); - if ((e.flags() & CRT_INVOKE) != 0) + if ((e.flags() & FLAG_INVOKE) != 0) print(", invoke"); - if ((e.flags() & CRT_CREATE) != 0) + if ((e.flags() & FLAG_CREATE) != 0) print(", create"); - if ((e.flags() & CRT_BRANCH_TRUE) != 0) + if ((e.flags() & FLAG_BRANCH_TRUE) != 0) print(", branch-true"); - if ((e.flags() & CRT_BRANCH_FALSE) != 0) + if ((e.flags() & FLAG_BRANCH_FALSE) != 0) print(", branch-false"); println(); } @@ -705,13 +706,13 @@ void printMap(String name, List map, CodeAttribute lr) { String mapTypeName(SimpleVerificationTypeInfo type) { return switch (type) { - case ITEM_TOP -> "top"; - case ITEM_INTEGER -> "int"; - case ITEM_FLOAT -> "float"; - case ITEM_LONG -> "long"; - case ITEM_DOUBLE -> "double"; - case ITEM_NULL -> "null"; - case ITEM_UNINITIALIZED_THIS -> "this"; + case TOP -> "top"; + case INTEGER -> "int"; + case FLOAT -> "float"; + case LONG -> "long"; + case DOUBLE -> "double"; + case NULL -> "null"; + case UNINITIALIZED_THIS -> "this"; }; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index 764f93bd54aeb..77fbce8839e72 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -741,7 +741,7 @@ static String getJavaName(String name) { */ String getConstantValue(ClassDesc d, ConstantValueEntry cpInfo) { switch (cpInfo.tag()) { - case ClassFile.TAG_INTEGER: { + case PoolEntry.TAG_INTEGER: { var val = (Integer)cpInfo.constantValue(); switch (d.descriptorString()) { case "C": @@ -755,7 +755,7 @@ String getConstantValue(ClassDesc d, ConstantValueEntry cpInfo) { return String.valueOf(val); } } - case ClassFile.TAG_STRING: + case PoolEntry.TAG_STRING: return getConstantStringValue(cpInfo.constantValue().toString()); default: return constantWriter.stringValue(cpInfo); diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java index c649ce982969e..b3c6b5b6c640d 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ConstantWriter.java @@ -26,7 +26,8 @@ package com.sun.tools.javap; import java.lang.classfile.constantpool.*; -import static java.lang.classfile.ClassFile.*; + +import static java.lang.classfile.constantpool.PoolEntry.*; /* * Write a constant pool entry. @@ -156,13 +157,13 @@ String cpTagName(int tag) { case TAG_CLASS -> "Class"; case TAG_STRING -> "String"; case TAG_FIELDREF -> "Fieldref"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; case TAG_METHODREF -> "Methodref"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethodref"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_NAMEANDTYPE -> "NameAndType"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethodref"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_NAME_AND_TYPE -> "NameAndType"; default -> "Unknown"; }; } @@ -177,13 +178,13 @@ String tagName(int tag) { case TAG_CLASS -> "class"; case TAG_STRING -> "String"; case TAG_FIELDREF -> "Field"; - case TAG_METHODHANDLE -> "MethodHandle"; - case TAG_METHODTYPE -> "MethodType"; + case TAG_METHOD_HANDLE -> "MethodHandle"; + case TAG_METHOD_TYPE -> "MethodType"; case TAG_METHODREF -> "Method"; - case TAG_INTERFACEMETHODREF -> "InterfaceMethod"; - case TAG_INVOKEDYNAMIC -> "InvokeDynamic"; - case TAG_CONSTANTDYNAMIC -> "Dynamic"; - case TAG_NAMEANDTYPE -> "NameAndType"; + case TAG_INTERFACE_METHODREF -> "InterfaceMethod"; + case TAG_INVOKE_DYNAMIC -> "InvokeDynamic"; + case TAG_DYNAMIC -> "Dynamic"; + case TAG_NAME_AND_TYPE -> "NameAndType"; default -> "(unknown tag " + tag + ")"; }; } diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java index a1d939bcc4f23..d899569724e66 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/StackMapWriter.java @@ -122,25 +122,25 @@ void print(StackMapFrameInfo.VerificationTypeInfo entry, boolean firstThis) { switch (entry) { case StackMapFrameInfo.SimpleVerificationTypeInfo s -> { switch (s) { - case ITEM_TOP -> + case TOP -> print("top"); - case ITEM_INTEGER -> + case INTEGER -> print("int"); - case ITEM_FLOAT -> + case FLOAT -> print("float"); - case ITEM_LONG -> + case LONG -> print("long"); - case ITEM_DOUBLE -> + case DOUBLE -> print("double"); - case ITEM_NULL -> + case NULL -> print("null"); - case ITEM_UNINITIALIZED_THIS -> + case UNINITIALIZED_THIS -> print("uninit_this"); } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java index d0b95df848474..516d094b5daa8 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/AbstractDCmd.java @@ -30,7 +30,6 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.time.Duration; -import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Comparator; import java.util.List; @@ -288,41 +287,4 @@ protected final String exampleDirectory() { return "/directory/recordings"; } } - - static String expandFilename(String filename) { - if (filename == null || filename.indexOf('%') == -1) { - return filename; - } - - String pid = null; - String time = null; - StringBuilder sb = new StringBuilder(); - for (int i = 0; i < filename.length(); i++) { - char c = filename.charAt(i); - if (c == '%' && i < filename.length() - 1) { - char nc = filename.charAt(i + 1); - if (nc == '%') { // %% ==> % - sb.append('%'); - i++; - } else if (nc == 'p') { - if (pid == null) { - pid = JVM.getPid(); - } - sb.append(pid); - i++; - } else if (nc == 't') { - if (time == null) { - time = ValueFormatter.formatDateTime(LocalDateTime.now()); - } - sb.append(time); - i++; - } else { - sb.append('%'); - } - } else { - sb.append(c); - } - } - return sb.toString(); - } } diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java index 43a8bb96874b8..151456745b0ac 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/ArgumentParser.java @@ -25,14 +25,18 @@ package jdk.jfr.internal.dcmd; +import java.time.LocalDateTime; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringJoiner; + +import jdk.jfr.internal.JVM; import jdk.jfr.internal.util.SpellChecker; import jdk.jfr.internal.util.TimespanUnit; +import jdk.jfr.internal.util.ValueFormatter; final class ArgumentParser { private final Map options = new HashMap<>(); @@ -226,10 +230,54 @@ private Object value(String name, String type, String text) { case "BOOLEAN" -> parseBoolean(name, text); case "NANOTIME" -> parseNanotime(name, text); case "MEMORY SIZE" -> parseMemorySize(name, text); + case "FILE" -> text == null ? "" : parseFilename(text); default -> throw new InternalError("Unknown type: " + type); }; } + /** + * Expands filename arguments replacing '%p' with the PID + * and '%t' with the time in 'yyyy_MM_dd_HH_mm_ss' format. + * @param filename a filename to be expanded + * @return filename with expanded arguments + */ + private String parseFilename(String filename) { + if (filename == null || filename.indexOf('%') == -1) { + return filename; + } + + String pid = null; + String time = null; + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < filename.length(); i++) { + char c = filename.charAt(i); + if (c == '%' && i < filename.length() - 1) { + char nc = filename.charAt(i + 1); + if (nc == '%') { // %% ==> % + sb.append('%'); + i++; + } else if (nc == 'p') { + if (pid == null) { + pid = JVM.getPid(); + } + sb.append(pid); + i++; + } else if (nc == 't') { + if (time == null) { + time = ValueFormatter.formatDateTime(LocalDateTime.now()); + } + sb.append(time); + i++; + } else { + sb.append('%'); + } + } else { + sb.append(c); + } + } + return sb.toString(); + } + private Long parseLong(String name, String text) { if (text == null) { throw new IllegalArgumentException("Parsing error long value: syntax error, value is null"); diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java index 30d916b30e5dd..7f68ba7ee7951 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdDump.java @@ -55,7 +55,7 @@ final class DCmdDump extends AbstractDCmd { public void execute(ArgumentParser parser) throws DCmdException { parser.checkUnknownArguments(); String name = parser.getOption("name"); - String filename = expandFilename(parser.getOption("filename")); + String filename = parser.getOption("filename"); Long maxAge = parser.getOption("maxage"); Long maxSize = parser.getOption("maxsize"); String begin = parser.getOption("begin"); @@ -230,7 +230,7 @@ public String[] getHelp() { dumped. If no filename is given, a filename is generated from the PID and the current date. The filename may also be a directory in which case, the filename is generated from the PID and the current date in - the specified directory. (STRING, no default value) + the specified directory. (FILE, no default value) Note: If a filename is given, '%%p' in the filename will be replaced by the PID, and '%%t' will be replaced by the time in @@ -284,7 +284,7 @@ public Argument[] getArgumentInfos() { "STRING", false, true, null, false), new Argument("filename", "Copy recording data to file, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, null, false), + "FILE", false, true, null, false), new Argument("maxage", "Maximum duration to dump, in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, true, null, false), diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java index 8424fa4a811eb..26c095541b6aa 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStart.java @@ -80,7 +80,7 @@ public void execute(ArgumentParser parser) throws DCmdException { Long delay = parser.getOption("delay"); Long duration = parser.getOption("duration"); Boolean disk = parser.getOption("disk"); - String path = expandFilename(parser.getOption("filename")); + String path = parser.getOption("filename"); Long maxAge = parser.getOption("maxage"); Long maxSize = parser.getOption("maxsize"); Long flush = parser.getOption("flush-interval"); @@ -377,7 +377,7 @@ Virtual Machine (JVM) shuts down. If set to 'true' and no value placed in the directory where the process was started. The filename may also be a directory in which case, the filename is generated from the PID and the current date in the specified - directory. (STRING, no default value) + directory. (FILE, no default value) Note: If a filename is given, '%p' in the filename will be replaced by the PID, and '%t' will be replaced by the time in @@ -501,7 +501,7 @@ public Argument[] getArgumentInfos() { "BOOLEAN", false, true, "true", false), new Argument("filename", "Resulting recording filename, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, "hotspot-pid-xxxxx-id-y-YYYY_MM_dd_HH_mm_ss.jfr", false), + "FILE", false, true, "hotspot-pid-xxxxx-id-y-YYYY_MM_dd_HH_mm_ss.jfr", false), new Argument("maxage", "Maximum time to keep recorded data (on disk) in (s)econds, (m)inutes, (h)ours, or (d)ays, e.g. 60m, or 0 for no limit", "NANOTIME", false, true, "0", false), diff --git a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java index 92d2d28b4721a..5cf983645c65c 100644 --- a/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java +++ b/src/jdk.jfr/share/classes/jdk/jfr/internal/dcmd/DCmdStop.java @@ -44,7 +44,7 @@ final class DCmdStop extends AbstractDCmd { protected void execute(ArgumentParser parser) throws DCmdException { parser.checkUnknownArguments(); String name = parser.getOption("name"); - String filename = expandFilename(parser.getOption("filename")); + String filename = parser.getOption("filename"); try { Recording recording = findRecording(name); WriteableUserPath path = PrivateAccess.getInstance().getPlatformRecording(recording).getDestination(); @@ -80,7 +80,7 @@ public String[] getHelp() { filename (Optional) Name of the file to which the recording is written when the recording is stopped. If no path is provided, the data from the recording - is discarded. (STRING, no default value) + is discarded. (FILE, no default value) Note: If a path is given, '%%p' in the path will be replaced by the PID, and '%%t' will be replaced by the time in 'yyyy_MM_dd_HH_mm_ss' format. @@ -107,7 +107,7 @@ public Argument[] getArgumentInfos() { "STRING", true, true, null, false), new Argument("filename", "Copy recording data to file, e.g. \\\"" + exampleFilename() + "\\\"", - "STRING", false, true, null, false) + "FILE", false, true, null, false) }; } } diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java index 4edc90a97b7be..9b9e7ad1ce893 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/IncludeLocalesPlugin.java @@ -33,6 +33,8 @@ import java.util.Map; import java.util.Objects; import java.util.Optional; + +import static java.lang.classfile.constantpool.PoolEntry.*; import static java.util.ResourceBundle.Control; import java.util.Set; import java.util.function.IntUnaryOperator; @@ -41,7 +43,7 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; import java.util.stream.Stream; -import static java.lang.classfile.ClassFile.*; + import jdk.tools.jlink.internal.ResourcePrevisitor; import jdk.tools.jlink.internal.StringTable; import jdk.tools.jlink.plugin.ResourcePoolModule; @@ -300,18 +302,18 @@ private boolean stripUnsupportedLocales(byte[] bytes) { } case TAG_CLASS, TAG_STRING, - TAG_METHODTYPE, + TAG_METHOD_TYPE, TAG_MODULE, TAG_PACKAGE -> offset += 3; - case TAG_METHODHANDLE -> offset += 4; + case TAG_METHOD_HANDLE -> offset += 4; case TAG_INTEGER, TAG_FLOAT, TAG_FIELDREF, TAG_METHODREF, - TAG_INTERFACEMETHODREF, - TAG_NAMEANDTYPE, - TAG_CONSTANTDYNAMIC, - TAG_INVOKEDYNAMIC -> offset += 5; + TAG_INTERFACE_METHODREF, + TAG_NAME_AND_TYPE, + TAG_DYNAMIC, + TAG_INVOKE_DYNAMIC -> offset += 5; case TAG_LONG, TAG_DOUBLE -> {offset += 9; cpSlot++;} //additional slot for double and long entries default -> throw new IllegalArgumentException("Unknown constant pool entry: 0x" diff --git a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java index 6f8bc9b7779bf..71c509e7deafd 100644 --- a/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java +++ b/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/plugins/StringSharingPlugin.java @@ -51,6 +51,8 @@ import jdk.tools.jlink.internal.ResourcePrevisitor; import jdk.tools.jlink.internal.StringTable; +import static java.lang.classfile.constantpool.PoolEntry.*; + /** * * A Plugin that stores the image classes constant pool UTF_8 entries into the @@ -214,7 +216,7 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource int tag = stream.readUnsignedByte(); byte[] arr; switch (tag) { - case ClassFile.TAG_UTF8: { + case TAG_UTF8: { String original = stream.readUTF(); // 2 cases, a Descriptor or a simple String if (descriptorIndexes.contains(i)) { @@ -238,8 +240,8 @@ private byte[] optimize(ResourcePoolEntry resource, ResourcePoolBuilder resource break; } - case ClassFile.TAG_LONG: - case ClassFile.TAG_DOUBLE: + case TAG_LONG: + case TAG_DOUBLE: i++; default: { out.write(tag); diff --git a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java index bed20ec1190ea..2e37a5c91af32 100644 --- a/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java +++ b/src/jdk.jpackage/share/classes/jdk/jpackage/internal/I18N.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 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 @@ -24,36 +24,64 @@ */ package jdk.jpackage.internal; +import java.util.ArrayList; +import java.util.List; +import java.util.ListResourceBundle; +import java.util.Map; import jdk.internal.util.OperatingSystem; import java.util.ResourceBundle; +import static java.util.stream.Collectors.toMap; +import java.util.stream.Stream; class I18N { static String getString(String key) { - if (PLATFORM.containsKey(key)) { - return PLATFORM.getString(key); - } - return SHARED.getString(key); + return BUNDLE.getString(key); } - private static final ResourceBundle SHARED = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MainResources"); + private static class MultiResourceBundle extends ListResourceBundle { + + MultiResourceBundle(ResourceBundle... bundles) { + contents = Stream.of(bundles).map(bundle -> { + return bundle.keySet().stream().map(key -> { + return Map.entry(key, bundle.getObject(key)); + }); + }).flatMap(x -> x).collect(toMap(Map.Entry::getKey, Map.Entry::getValue, (o, n) -> { + // Override old value with the new one + return n; + })).entrySet().stream().map(e -> { + return new Object[]{e.getKey(), e.getValue()}; + }).toArray(Object[][]::new); + } + + @Override + protected Object[][] getContents() { + return contents; + } + + private final Object[][] contents; + } - private static final ResourceBundle PLATFORM; + private static final MultiResourceBundle BUNDLE; static { + List bundleNames = new ArrayList<>(); + + bundleNames.add("jdk.jpackage.internal.resources.MainResources"); + if (OperatingSystem.isLinux()) { - PLATFORM = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.LinuxResources"); + bundleNames.add("jdk.jpackage.internal.resources.LinuxResources"); } else if (OperatingSystem.isWindows()) { - PLATFORM = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.WinResources"); + bundleNames.add("jdk.jpackage.internal.resources.WinResources"); + bundleNames.add("jdk.jpackage.internal.resources.WinResourcesNoL10N"); } else if (OperatingSystem.isMacOS()) { - PLATFORM = ResourceBundle.getBundle( - "jdk.jpackage.internal.resources.MacResources"); + bundleNames.add("jdk.jpackage.internal.resources.MacResources"); } else { throw new IllegalStateException("Unknown platform"); } + + BUNDLE = new MultiResourceBundle(bundleNames.stream().map(ResourceBundle::getBundle) + .toArray(ResourceBundle[]::new)); } } diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties index 5843a750adea9..9e7504364d35a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources.properties @@ -35,7 +35,6 @@ resource.setup-icon=setup dialog icon resource.post-app-image-script=script to run after application image is populated resource.post-msi-script=script to run after msi file for exe installer is created resource.wxl-file=WiX localization file -resource.wxl-file-name=MsiInstallerStrings_en.wxl resource.main-wix-file=Main WiX project file resource.overrides-wix-file=Overrides WiX project file resource.shortcutpromptdlg-wix-file=Shortcut prompt dialog WiX project file diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N.properties new file mode 100644 index 0000000000000..9bb545b942fe2 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N.properties @@ -0,0 +1,28 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# +# + + +resource.wxl-file-name=MsiInstallerStrings_en.wxl diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_de.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_de.properties new file mode 100644 index 0000000000000..aa3aebf8cc482 --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_de.properties @@ -0,0 +1,28 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# +# + + +resource.wxl-file-name=MsiInstallerStrings_de.wxl diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_ja.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_ja.properties new file mode 100644 index 0000000000000..3162e29f4ca9c --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_ja.properties @@ -0,0 +1,28 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# +# + + +resource.wxl-file-name=MsiInstallerStrings_ja.wxl diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_zh_CN.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_zh_CN.properties new file mode 100644 index 0000000000000..cc96dba78dbdb --- /dev/null +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResourcesNoL10N_zh_CN.properties @@ -0,0 +1,28 @@ +# +# 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. Oracle designates this +# particular file as subject to the "Classpath" exception as provided +# by Oracle in the LICENSE file that accompanied this code. +# +# 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. +# +# + + +resource.wxl-file-name=MsiInstallerStrings_zh_CN.wxl diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_de.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_de.properties index e0c15bfb8fba2..a7212d9640a7a 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_de.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_de.properties @@ -35,7 +35,6 @@ resource.setup-icon=Symbol für Dialogfeld "Setup" resource.post-app-image-script=Auszuführendes Skript nach dem Auffüllen des Anwendungsimages resource.post-msi-script=Auszuführendes Skript nach dem Erstellen der MSI-Datei für das EXE-Installationsprogramm resource.wxl-file=WiX-Lokalisierungsdatei -resource.wxl-file-name=MsiInstallerStrings_de.wxl resource.main-wix-file=Haupt-WiX-Projektdatei resource.overrides-wix-file=Überschreibt WiX-Projektdatei resource.shortcutpromptdlg-wix-file=Dialogfeld für Verknüpfungs-Prompt der WiX-Projektdatei diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties index e0bcd18c81103..352aab7a4934b 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_ja.properties @@ -35,7 +35,6 @@ resource.setup-icon=設定ダイアログ・アイコン resource.post-app-image-script=アプリケーション・イメージを移入した後に実行するスクリプト resource.post-msi-script=exeインストーラのmsiファイルが作成された後に実行するスクリプト resource.wxl-file=WiXローカリゼーション・ファイル -resource.wxl-file-name=MsiInstallerStrings_ja.wxl resource.main-wix-file=メインWiXプロジェクト・ファイル resource.overrides-wix-file=WiXプロジェクト・ファイルのオーバーライド resource.shortcutpromptdlg-wix-file=ショートカット・プロンプト・ダイアログWiXプロジェクト・ファイル diff --git a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties index e2b8bd37135f4..a8d4a4471d6d0 100644 --- a/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties +++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/resources/WinResources_zh_CN.properties @@ -35,7 +35,6 @@ resource.setup-icon=设置对话框图标 resource.post-app-image-script=要在填充应用程序映像之后运行的脚本 resource.post-msi-script=在为 exe 安装程序创建 msi 文件之后要运行的脚本 resource.wxl-file=WiX 本地化文件 -resource.wxl-file-name=MsiInstallerStrings_zh_CN.wxl resource.main-wix-file=主 WiX 项目文件 resource.overrides-wix-file=覆盖 WiX 项目文件 resource.shortcutpromptdlg-wix-file=快捷方式提示对话框 WiX 项目文件 diff --git a/test/hotspot/gtest/gc/shared/test_oopStorageSet.cpp b/test/hotspot/gtest/gc/shared/test_oopStorageSet.cpp index c8ada2574c0e7..947ff120d15fe 100644 --- a/test/hotspot/gtest/gc/shared/test_oopStorageSet.cpp +++ b/test/hotspot/gtest/gc/shared/test_oopStorageSet.cpp @@ -23,15 +23,21 @@ */ #include "precompiled.hpp" -#include "gc/shared/oopStorage.hpp" +#include "gc/shared/oopStorage.inline.hpp" #include "gc/shared/oopStorageSet.hpp" #include "memory/allocation.inline.hpp" +#include "runtime/interfaceSupport.inline.hpp" +#include "runtime/vmOperations.hpp" +#include "runtime/vmThread.hpp" #include "utilities/debug.hpp" #include "utilities/enumIterator.hpp" #include "utilities/globalDefinitions.hpp" #include "utilities/macros.hpp" #include "unittest.hpp" +using ::testing::HasSubstr; +using ::testing::Not; + class OopStorageSetTest : public ::testing::Test { protected: // Returns index of s in storages, or size if not found. @@ -83,6 +89,8 @@ class OopStorageSetTest : public ::testing::Test { EnumRange(), &OopStorageSet::fill_all); } + + class VM_PrintAtSafepoint; }; TEST_VM_F(OopStorageSetTest, strong_iteration) { @@ -96,3 +104,77 @@ TEST_VM_F(OopStorageSetTest, weak_iteration) { TEST_VM_F(OopStorageSetTest, all_iteration) { test_all_iteration(); } + +class OopStorageSetTest::VM_PrintAtSafepoint : public VM_GTestExecuteAtSafepoint { +private: + class PrintContainingClosure : public Closure { + public: + void do_oop(oop* addr) { + // Direct slot hit. + { + stringStream ss; + bool printed = OopStorageSet::print_containing(addr, &ss); + ASSERT_TRUE(printed); + ASSERT_THAT(ss.freeze(), HasSubstr("is a pointer")); + ASSERT_THAT(ss.freeze(), HasSubstr("into block")); + ASSERT_THAT(ss.freeze(), HasSubstr("in oop storage")); + ASSERT_THAT(ss.freeze(), Not(HasSubstr("(unaligned)"))); + } + + // Unaligned pointer to adjacent slot, should still be in oop storage range. + { + char* unaligned_addr = (char*)addr + 1; + stringStream ss; + bool printed = OopStorageSet::print_containing(unaligned_addr, &ss); + ASSERT_TRUE(printed); + ASSERT_THAT(ss.freeze(), HasSubstr("is a pointer")); + ASSERT_THAT(ss.freeze(), HasSubstr("into block")); + ASSERT_THAT(ss.freeze(), HasSubstr("in oop storage")); + ASSERT_THAT(ss.freeze(), HasSubstr("(unaligned)")); + } + } + }; + +public: + void doit() { + PrintContainingClosure cl; + for (OopStorage* storage : OopStorageSet::Range()) { + storage->oops_do(&cl); + } + } +}; + +TEST_VM_F(OopStorageSetTest, print_containing) { + // nullptrs print nothing + { + stringStream ss; + bool printed = OopStorageSet::print_containing(nullptr, &ss); + ASSERT_FALSE(printed); + EXPECT_STREQ("", ss.freeze()); + } + + // Goofy values print nothing: unaligned out of storage pointer. + { + stringStream ss; + bool printed = OopStorageSet::print_containing((char*)0x1, &ss); + ASSERT_FALSE(printed); + EXPECT_STREQ("", ss.freeze()); + } + + // Goofy values print nothing: aligned out of storage pointer. + { + stringStream ss; + bool printed = OopStorageSet::print_containing((char*)alignof(oop), &ss); + ASSERT_FALSE(printed); + EXPECT_STREQ("", ss.freeze()); + } + + // All slot addresses should print well. + { + VM_PrintAtSafepoint op; + { + ThreadInVMfromNative invm(JavaThread::current()); + VMThread::execute(&op); + } + } +} diff --git a/test/hotspot/jtreg/ProblemList.txt b/test/hotspot/jtreg/ProblemList.txt index 2086bc2ed054b..aefe09fd3aec2 100644 --- a/test/hotspot/jtreg/ProblemList.txt +++ b/test/hotspot/jtreg/ProblemList.txt @@ -43,6 +43,7 @@ # :hotspot_compiler +applications/ctw/modules/java_base.java 8340683 generic-all compiler/ciReplay/TestSAServer.java 8029528 generic-all compiler/compilercontrol/jcmd/ClearDirectivesFileStackTest.java 8225370 generic-all @@ -115,7 +116,6 @@ runtime/os/TestTracePageSizes.java#Serial 8267460 linux-aarch64 runtime/ErrorHandling/CreateCoredumpOnCrash.java 8267433 macosx-x64 runtime/StackGuardPages/TestStackGuardPagesNative.java 8303612 linux-all runtime/ErrorHandling/MachCodeFramesInErrorFile.java 8313315 linux-ppc64le -runtime/Thread/TestAlwaysPreTouchStacks.java 8335167 macosx-aarch64 runtime/cds/appcds/customLoader/HelloCustom_JFR.java 8241075 linux-all,windows-x64 applications/jcstress/copy.java 8229852 linux-all @@ -136,6 +136,8 @@ serviceability/jvmti/vthread/GetThreadStateMountedTest/GetThreadStateMountedTest serviceability/jvmti/vthread/GetSetLocalTest/GetSetLocalTest.java 8286836 generic-all serviceability/jvmti/vthread/CarrierThreadEventNotification/CarrierThreadEventNotification.java 8333681 generic-all serviceability/dcmd/gc/RunFinalizationTest.java 8227120 generic-all +serviceability/dcmd/vm/SystemDumpMapTest.java 8340401 windows-all +serviceability/dcmd/vm/SystemMapTest.java 8340401 windows-all serviceability/sa/ClhsdbCDSCore.java 8267433,8318754 macosx-x64,macosx-aarch64 serviceability/sa/ClhsdbFindPC.java#xcomp-core 8267433,8318754 macosx-x64,macosx-aarch64 @@ -172,6 +174,7 @@ vmTestbase/nsk/jvmti/scenarios/capability/CM03/cm03t001/TestDescription.java 807 vmTestbase/nsk/jvmti/InterruptThread/intrpthrd003/TestDescription.java 8288911 macosx-all vmTestbase/gc/lock/jni/jnilock002/TestDescription.java 8192647 generic-all +vmTestbase/gc/memory/Nio/Nio.java 8340728 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening001.java 8148743 generic-all vmTestbase/jit/escape/LockCoarsening/LockCoarsening002.java 8208259 generic-all diff --git a/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java b/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java index 544f84c9b2726..ccf4822e6769b 100644 --- a/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java +++ b/test/hotspot/jtreg/compiler/arguments/TestStressOptions.java @@ -24,7 +24,7 @@ /* * @test * @key stress randomness - * @bug 8252219 8256535 8317349 + * @bug 8252219 8256535 8317349 8319879 8335334 * @requires vm.compiler2.enabled * @summary Tests that different combinations of stress options and * -XX:StressSeed=N are accepted. @@ -48,6 +48,14 @@ * compiler.arguments.TestStressOptions * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressMacroExpansion -XX:StressSeed=42 * compiler.arguments.TestStressOptions + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressIncrementalInlining + * compiler.arguments.TestStressOptions + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressIncrementalInlining -XX:StressSeed=42 + * compiler.arguments.TestStressOptions + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps + * compiler.arguments.TestStressOptions + * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:+StressUnstableIfTraps -XX:StressSeed=42 + * compiler.arguments.TestStressOptions */ package compiler.arguments; diff --git a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java index 9b91375acb73e..b5a27f3f714b3 100644 --- a/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java +++ b/test/hotspot/jtreg/compiler/c2/irTests/TestPrunedExHandler.java @@ -29,6 +29,7 @@ * @test * @bug 8267532 * @summary check that uncommon trap is generated for unhandled catch block + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib / * @requires vm.opt.DeoptimizeALot != true * @run driver compiler.c2.irTests.TestPrunedExHandler diff --git a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java index 068da4100bd69..87ce9a313a8b8 100644 --- a/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java +++ b/test/hotspot/jtreg/compiler/cha/StrengthReduceInterfaceCall.java @@ -24,6 +24,7 @@ /* * @test * @requires !vm.graal.enabled + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc * java.base/jdk.internal.vm.annotation diff --git a/test/hotspot/jtreg/compiler/cha/TypeProfileFinalMethod.java b/test/hotspot/jtreg/compiler/cha/TypeProfileFinalMethod.java new file mode 100644 index 0000000000000..a81ba53af52c7 --- /dev/null +++ b/test/hotspot/jtreg/compiler/cha/TypeProfileFinalMethod.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2021, 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 + * 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 + * @summary test c1 to record type profile with CHA optimization + * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == null | vm.opt.TieredStopAtLevel == 4) + * @library /test/lib + * @build jdk.test.whitebox.WhiteBox + * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox + * @run driver compiler.cha.TypeProfileFinalMethod + */ +package compiler.cha; + +import java.io.File; +import java.util.regex.Pattern; +import java.util.regex.Matcher; +import jdk.test.lib.Asserts; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; +import jdk.test.whitebox.WhiteBox; + +public class TypeProfileFinalMethod { + public static void main(String[] args) throws Exception { + ProcessBuilder pb = ProcessTools.createTestJavaProcessBuilder( + "-Xbootclasspath/a:.", + "-Xbatch", "-XX:-UseOnStackReplacement", + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", + "-XX:Tier3InvocationThreshold=200", "-XX:Tier4InvocationThreshold=5000", + Launcher.class.getName()); + OutputAnalyzer output = ProcessTools.executeProcess(pb); + System.out.println("debug output"); + System.out.println(output.getOutput()); + System.out.println("debug output end"); + output.shouldHaveExitValue(0); + output.shouldNotContain("failed to inline: virtual call"); + Pattern pattern = Pattern.compile("Child1::m.* inline "); + Matcher matcher = pattern.matcher(output.getOutput()); + int matchCnt = 0; + while (matcher.find()) { + matchCnt++; + } + Asserts.assertEquals(matchCnt, 2); // inline Child1::m() twice + } + + static class Launcher { + public static void main(String[] args) throws Exception { + addCompilerDirectives(); + int cnt = 5300; + // warmup test1 to be compiled with c1 and c2 + // and only compile test2 with c1 + for (int i = 0; i < cnt; i++) { + test1(i); + } + for (int i = 0; i < cnt; i++) { + test2(i); + } + Parent c = new TypeProfileFinalMethod.Child2(); + System.out.println("======== break CHA"); + // trigger c2 to compile test2 + for (int i = 0; i < 100; i++) { + test2(i); + } + } + + static void addCompilerDirectives() { + WhiteBox WB = WhiteBox.getWhiteBox(); + // do not inline getInstance() for test1() and test2() + String directive = "[{ match: [\"" + Launcher.class.getName() + "::test1\"]," + + "inline:[\"-" + Launcher.class.getName()+"::getInstance()\"] }]"; + WB.addCompilerDirective(directive); + + directive = "[{ match: [\"" + Launcher.class.getName() + "::test2\"]," + + "inline:[\"-" + Launcher.class.getName()+"::getInstance()\"] }]"; + WB.addCompilerDirective(directive); + + // do not inline test1() for test2() in c1 compilation + directive = "[{ match: [\"" + Launcher.class.getName() + "::test2\"]," + + "c1: { inline:[\"-" + Launcher.class.getName()+"::test1()\"] } }]"; + WB.addCompilerDirective(directive); + + // print inline tree for checking + directive = "[{ match: [\"" + Launcher.class.getName() + "::test2\"]," + + "c2: { PrintInlining: true } }]"; + WB.addCompilerDirective(directive); + } + + static int test1(int i) { + int ret = 0; + Parent ix = getInstance(); + if (i<200) { + return ix.m(); + } + for (int j = 0; j < 50; j++) { + ret += ix.m(); // the callsite we are interesting + } + return ret; + } + + static int test2(int i) { + return test1(i); + } + + static Parent getInstance() { + return new TypeProfileFinalMethod.Child1(); + } + } + + static abstract class Parent { + abstract public int m(); + } + + final static class Child1 extends Parent { + public int m() { + return 1; + } + } + + final static class Child2 extends Parent { + public int m() { + return 2; + } + } +} + + diff --git a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java index 5855440d0b275..1dcef0c96cd64 100644 --- a/test/hotspot/jtreg/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java +++ b/test/hotspot/jtreg/compiler/jvmci/compilerToVM/MaterializeVirtualObjectTest.java @@ -27,6 +27,7 @@ * * @requires vm.jvmci & vm.compMode == "Xmixed" * @requires vm.opt.final.EliminateAllocations == true + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * * @comment no "-Xcomp -XX:-TieredCompilation" combination allowed until JDK-8140018 is resolved * @requires vm.opt.TieredCompilation == null | vm.opt.TieredCompilation == true diff --git a/test/hotspot/jtreg/compiler/rangechecks/TestExplicitRangeChecks.java b/test/hotspot/jtreg/compiler/rangechecks/TestExplicitRangeChecks.java index ba045814fc2dd..83bfd63c629c6 100644 --- a/test/hotspot/jtreg/compiler/rangechecks/TestExplicitRangeChecks.java +++ b/test/hotspot/jtreg/compiler/rangechecks/TestExplicitRangeChecks.java @@ -25,6 +25,7 @@ * @test * @bug 8073480 * @summary explicit range checks should be recognized by C2 + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib / * @modules java.base/jdk.internal.misc:+open * @build jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java b/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java index 5fee59c751079..626f4c9b1f6aa 100644 --- a/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java +++ b/test/hotspot/jtreg/compiler/uncommontrap/TestUnstableIfTrap.java @@ -24,7 +24,7 @@ /* * @test * @bug 8030976 8059226 - * @requires !vm.graal.enabled + * @requires !vm.graal.enabled & (vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps) * @library /test/lib / * @modules java.base/jdk.internal.org.objectweb.asm * java.base/jdk.internal.misc diff --git a/test/hotspot/jtreg/compiler/unsafe/UnsafeGetStableArrayElement.java b/test/hotspot/jtreg/compiler/unsafe/UnsafeGetStableArrayElement.java index 931b1a10e0bd7..bef57605f5f55 100644 --- a/test/hotspot/jtreg/compiler/unsafe/UnsafeGetStableArrayElement.java +++ b/test/hotspot/jtreg/compiler/unsafe/UnsafeGetStableArrayElement.java @@ -244,9 +244,9 @@ static void testUnsafeAccess() throws Exception { testMismatched(Test::testZ_S, Test::changeZ); testMismatched(Test::testZ_C, Test::changeZ); testMismatched(Test::testZ_I, Test::changeZ); - testMismatched(Test::testZ_J, Test::changeZ); + testMismatched(Test::testZ_J, Test::changeZ, false, ARRAY_BOOLEAN_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMismatched(Test::testZ_F, Test::changeZ); - testMismatched(Test::testZ_D, Test::changeZ); + testMismatched(Test::testZ_D, Test::changeZ, false, ARRAY_BOOLEAN_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // byte[], aligned accesses testMismatched(Test::testB_Z, Test::changeB); @@ -254,9 +254,9 @@ static void testUnsafeAccess() throws Exception { testMismatched(Test::testB_S, Test::changeB); testMismatched(Test::testB_C, Test::changeB); testMismatched(Test::testB_I, Test::changeB); - testMismatched(Test::testB_J, Test::changeB); + testMismatched(Test::testB_J, Test::changeB, false, ARRAY_BYTE_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMismatched(Test::testB_F, Test::changeB); - testMismatched(Test::testB_D, Test::changeB); + testMismatched(Test::testB_D, Test::changeB, false, ARRAY_BYTE_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // short[], aligned accesses testMismatched(Test::testS_Z, Test::changeS); @@ -264,9 +264,9 @@ static void testUnsafeAccess() throws Exception { testMatched( Test::testS_S, Test::changeS); testMismatched(Test::testS_C, Test::changeS); testMismatched(Test::testS_I, Test::changeS); - testMismatched(Test::testS_J, Test::changeS); + testMismatched(Test::testS_J, Test::changeS, false, ARRAY_SHORT_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMismatched(Test::testS_F, Test::changeS); - testMismatched(Test::testS_D, Test::changeS); + testMismatched(Test::testS_D, Test::changeS, false, ARRAY_SHORT_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // char[], aligned accesses testMismatched(Test::testC_Z, Test::changeC); @@ -274,9 +274,9 @@ static void testUnsafeAccess() throws Exception { testMismatched(Test::testC_S, Test::changeC); testMatched( Test::testC_C, Test::changeC); testMismatched(Test::testC_I, Test::changeC); - testMismatched(Test::testC_J, Test::changeC); + testMismatched(Test::testC_J, Test::changeC, false, ARRAY_CHAR_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMismatched(Test::testC_F, Test::changeC); - testMismatched(Test::testC_D, Test::changeC); + testMismatched(Test::testC_D, Test::changeC, false, ARRAY_CHAR_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // int[], aligned accesses testMismatched(Test::testI_Z, Test::changeI); @@ -284,9 +284,9 @@ static void testUnsafeAccess() throws Exception { testMismatched(Test::testI_S, Test::changeI); testMismatched(Test::testI_C, Test::changeI); testMatched( Test::testI_I, Test::changeI); - testMismatched(Test::testI_J, Test::changeI); + testMismatched(Test::testI_J, Test::changeI, false, ARRAY_INT_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMismatched(Test::testI_F, Test::changeI); - testMismatched(Test::testI_D, Test::changeI); + testMismatched(Test::testI_D, Test::changeI, false, ARRAY_INT_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // long[], aligned accesses testMismatched(Test::testJ_Z, Test::changeJ); @@ -304,9 +304,9 @@ static void testUnsafeAccess() throws Exception { testMismatched(Test::testF_S, Test::changeF); testMismatched(Test::testF_C, Test::changeF); testMismatched(Test::testF_I, Test::changeF); - testMismatched(Test::testF_J, Test::changeF); + testMismatched(Test::testF_J, Test::changeF, false, ARRAY_FLOAT_BASE_OFFSET == ARRAY_LONG_BASE_OFFSET); testMatched( Test::testF_F, Test::changeF); - testMismatched(Test::testF_D, Test::changeF); + testMismatched(Test::testF_D, Test::changeF, false, ARRAY_FLOAT_BASE_OFFSET == ARRAY_DOUBLE_BASE_OFFSET); // double[], aligned accesses testMismatched(Test::testD_Z, Test::changeD); diff --git a/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java b/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java index bb6185177e75f..18e7721e0d6c1 100644 --- a/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java +++ b/test/hotspot/jtreg/compiler/vectorization/runner/BasicBooleanOpTest.java @@ -25,6 +25,7 @@ /* * @test * @summary Vectorization test on basic boolean operations + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib / * * @build jdk.test.whitebox.WhiteBox diff --git a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeFramesTest.java b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeFramesTest.java index 1d9c8169d0433..91601479881c8 100644 --- a/test/hotspot/jtreg/compiler/whitebox/DeoptimizeFramesTest.java +++ b/test/hotspot/jtreg/compiler/whitebox/DeoptimizeFramesTest.java @@ -25,6 +25,7 @@ * @test DeoptimizeFramesTest * @bug 8028595 * @summary testing of WB::deoptimizeFrames() + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib / * @modules java.base/jdk.internal.misc * java.management diff --git a/test/hotspot/jtreg/containers/systemd/TEST.properties b/test/hotspot/jtreg/containers/systemd/TEST.properties new file mode 100644 index 0000000000000..d563e5f166403 --- /dev/null +++ b/test/hotspot/jtreg/containers/systemd/TEST.properties @@ -0,0 +1,24 @@ +# +# 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. +# + +exclusiveAccess.dirs=. diff --git a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java index bacd7a2078e97..6a9768de7e6e2 100644 --- a/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/x/TestAllocateHeapAt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -26,6 +26,7 @@ /* * @test TestAllocateHeapAt * @requires vm.gc.ZSinglegen & os.family == "linux" + * @requires !vm.opt.final.UseLargePages * @summary Test ZGC with -XX:AllocateHeapAt * @library /test/lib * @run main/othervm gc.x.TestAllocateHeapAt . true diff --git a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java index 28d2ebd6aea01..2fb040840b4da 100644 --- a/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java +++ b/test/hotspot/jtreg/gc/z/TestAllocateHeapAt.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 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 @@ -26,6 +26,7 @@ /* * @test TestAllocateHeapAt * @requires vm.gc.ZGenerational & os.family == "linux" + * @requires !vm.opt.final.UseLargePages * @summary Test ZGC with -XX:AllocateHeapAt * @library /test/lib * @run main/othervm gc.z.TestAllocateHeapAt . true diff --git a/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupBadCPIndex.jcod b/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupBadCPIndex.jcod new file mode 100644 index 0000000000000..4802548926b42 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupBadCPIndex.jcod @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/* Based on source: + * public class ContendedField { + * @Contended("group1") + * public int field; + * } + * + * We change the value of "value" so it refers to an invalid CP entry + */ + +class BadContendedGroupBadCPIndex { + 0xCAFEBABE; + 0; // minor version + 65; // version + [19] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadContendedGroupBadCPIndex"; // #8 at 0x3C + Utf8 "field"; // #9 at 0x4D + Utf8 "I"; // #10 at 0x55 + Utf8 "RuntimeVisibleAnnotations"; // #11 at 0x59 + Utf8 "Ljdk/internal/vm/annotation/Contended;"; // #12 at 0x75 + Utf8 "value"; // #13 at 0x9E + Utf8 "group1"; // #14 at 0xA6 + Utf8 "Code"; // #15 at 0xAF + Utf8 "LineNumberTable"; // #16 at 0xB6 + Utf8 "SourceFile"; // #17 at 0xC8 + Utf8 "BadContendedGroupBadCPIndex.java"; // #18 at 0xD5 + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [1] { // Fields + { // field at 0xF5 + 0x0001; // access + #9; // name_index : field + #10; // descriptor_index : I + [1] { // Attributes + Attr(#11, 11) { // RuntimeVisibleAnnotations at 0xFD + [1] { // annotations + { // annotation + #12; + [1] { // element_value_pairs + { // element value pair + #13; + { // element_value + 's'; + #1400; // Changed from #14 to #1400 + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Fields + + [1] { // Methods + { // method at 0x0110 + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#15, 29) { // Code at 0x0118 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#16, 6) { // LineNumberTable at 0x012F + [1] { // line_number_table + 0 2; // at 0x013B + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#17, 2) { // SourceFile at 0x013D + #18; + } // end SourceFile + } // Attributes +} // end class BadContendedGroupBadCPIndex diff --git a/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupWrongType.jcod b/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupWrongType.jcod new file mode 100644 index 0000000000000..6fa53f939b3dd --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadContendedGroupWrongType.jcod @@ -0,0 +1,123 @@ +/* + * 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. + */ + +/* Based on source: + * public class ContendedField { + * @Contended("group1") + * public int field; + * } + * + * We change the value of "value" so it refers to the wrong type of CP entry + */ + +class BadContendedGroupWrongType { + 0xCAFEBABE; + 0; // minor version + 65; // version + [19] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadContendedGroupWrongType"; // #8 at 0x3C + Utf8 "field"; // #9 at 0x4D + Utf8 "I"; // #10 at 0x55 + Utf8 "RuntimeVisibleAnnotations"; // #11 at 0x59 + Utf8 "Ljdk/internal/vm/annotation/Contended;"; // #12 at 0x75 + Utf8 "value"; // #13 at 0x9E + Utf8 "group1"; // #14 at 0xA6 + Utf8 "Code"; // #15 at 0xAF + Utf8 "LineNumberTable"; // #16 at 0xB6 + Utf8 "SourceFile"; // #17 at 0xC8 + Utf8 "BadContendedGroupWrongType.java"; // #18 at 0xD5 + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [1] { // Fields + { // field at 0xF5 + 0x0001; // access + #9; // name_index : field + #10; // descriptor_index : I + [1] { // Attributes + Attr(#11, 11) { // RuntimeVisibleAnnotations at 0xFD + [1] { // annotations + { // annotation + #12; + [1] { // element_value_pairs + { // element value pair + #13; + { // element_value + 's'; + #7; // Changed from #14 (utf8) to #7 (class) + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Fields + + [1] { // Methods + { // method at 0x0110 + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#15, 29) { // Code at 0x0118 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#16, 6) { // LineNumberTable at 0x012F + [1] { // line_number_table + 0 2; // at 0x013B + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#17, 2) { // SourceFile at 0x013D + #18; + } // end SourceFile + } // Attributes +} // end class BadContendedGroupWrongType diff --git a/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtEnd.jcod b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtEnd.jcod new file mode 100644 index 0000000000000..991c4c832b3dc --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtEnd.jcod @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/* Based on source: + * + * public class DeprecatedMethod { + * @Deprecated(forRemoval=true, since="now") + * public static void m() {} + * } + * + * We add an extra junk member at the end. + */ + +class BadDeprecatedExtraMemberAtEnd { + 0xCAFEBABE; + 0; // minor version + 65; // version + [21] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadDeprecatedExtraMemberAtEnd"; // #8 at 0x3C + Utf8 "Code"; // #9 at 0x4F + Utf8 "LineNumberTable"; // #10 at 0x56 + Utf8 "m"; // #11 at 0x68 + Utf8 "Deprecated"; // #12 at 0x6C + Utf8 "RuntimeVisibleAnnotations"; // #13 at 0x79 + Utf8 "Ljava/lang/Deprecated;"; // #14 at 0x95 + Utf8 "forRemoval"; // #15 at 0xAE + int 0x00000001; // #16 at 0xBB + Utf8 "since"; // #17 at 0xC0 + Utf8 "now"; // #18 at 0xC8 + Utf8 "SourceFile"; // #19 at 0xCE + Utf8 "BadDeprecatedExtraMemberAtEnd.java"; // #20 at 0xDB + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // Fields + } // Fields + + [2] { // Methods + { // method at 0xFF + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0107 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x011E + [1] { // line_number_table + 0 1; // at 0x012A + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method at 0x012A + 0x0009; // access + #11; // name_index : m + #6; // descriptor_index : ()V + [3] { // Attributes + Attr(#9, 25) { // Code at 0x0132 + 0; // max_stack + 0; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0145 + [1] { // line_number_table + 0 4; // at 0x0151 + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#12, 0) { // Deprecated at 0x0151 + } // end Deprecated + ; + Attr(#13, 21) { // RuntimeVisibleAnnotations at 0x0157 (length changed from 16 to 21) + [1] { // annotations + { // annotation + #14; + [3] { // element_value_pairs <= extra pair added + { // element value pair + #15; + { // element_value + 'Z'; + #16; + } // element_value + } // element value pair + ; + { // element value pair + #17; + { // element_value + 's'; + #18; + } // element_value + } // element value pair + ; + { // Extra element value pair: now=true + #18; + { // element_value + 'Z'; + #16; + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#19, 2) { // SourceFile at 0x016F + #20; + } // end SourceFile + } // Attributes +} // end class BadDeprecatedExtraMemberAtEnd diff --git a/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtStart.jcod b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtStart.jcod new file mode 100644 index 0000000000000..0adf08049fd6e --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedExtraMemberAtStart.jcod @@ -0,0 +1,163 @@ +/* + * 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. + */ + +/* Based on source: + * + * public class DeprecatedMethod { + * @Deprecated(forRemoval=true, since="now") + * public static void m() {} + * } + * + * We add an extra junk member at the start. + */ + +class BadDeprecatedExtraMemberAtStart { + 0xCAFEBABE; + 0; // minor version + 65; // version + [21] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadDeprecatedExtraMemberAtStart"; // #8 at 0x3C + Utf8 "Code"; // #9 at 0x4F + Utf8 "LineNumberTable"; // #10 at 0x56 + Utf8 "m"; // #11 at 0x68 + Utf8 "Deprecated"; // #12 at 0x6C + Utf8 "RuntimeVisibleAnnotations"; // #13 at 0x79 + Utf8 "Ljava/lang/Deprecated;"; // #14 at 0x95 + Utf8 "forRemoval"; // #15 at 0xAE + int 0x00000001; // #16 at 0xBB + Utf8 "since"; // #17 at 0xC0 + Utf8 "now"; // #18 at 0xC8 + Utf8 "SourceFile"; // #19 at 0xCE + Utf8 "BadDeprecatedExtraMemberAtStart.java"; // #20 at 0xDB + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // Fields + } // Fields + + [2] { // Methods + { // method at 0xFF + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0107 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x011E + [1] { // line_number_table + 0 1; // at 0x012A + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method at 0x012A + 0x0009; // access + #11; // name_index : m + #6; // descriptor_index : ()V + [3] { // Attributes + Attr(#9, 25) { // Code at 0x0132 + 0; // max_stack + 0; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0145 + [1] { // line_number_table + 0 4; // at 0x0151 + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#12, 0) { // Deprecated at 0x0151 + } // end Deprecated + ; + Attr(#13, 21) { // RuntimeVisibleAnnotations at 0x0157 (length changed from 16 to 21) + [1] { // annotations + { // annotation + #14; + [3] { // element_value_pairs <= extra pair added + { // Extra element value pair: now=true + #18; + { // element_value + 'Z'; + #16; + } // element_value + } // element value pair + ; + { // element value pair + #15; + { // element_value + 'Z'; + #16; + } // element_value + } // element value pair + ; + { // element value pair + #17; + { // element_value + 's'; + #18; + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#19, 2) { // SourceFile at 0x016F + #20; + } // end SourceFile + } // Attributes +} // end class BadDeprecatedExtraMemberAtStart diff --git a/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalBadCPIndex.jcod b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalBadCPIndex.jcod new file mode 100644 index 0000000000000..e8648e0c705bb --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalBadCPIndex.jcod @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/* Based on source: + * + * public class DeprecatedMethod { + * @Deprecated(forRemoval=true, since="now") + * public static void m() {} + * } + * + * We change the CP index for the value of forRemoval to a junk value + */ + +class BadDeprecatedForRemovalBadCPIndex { + 0xCAFEBABE; + 0; // minor version + 65; // version + [21] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadDeprecatedForRemovalBadCPIndex"; // #8 at 0x3C + Utf8 "Code"; // #9 at 0x4F + Utf8 "LineNumberTable"; // #10 at 0x56 + Utf8 "m"; // #11 at 0x68 + Utf8 "Deprecated"; // #12 at 0x6C + Utf8 "RuntimeVisibleAnnotations"; // #13 at 0x79 + Utf8 "Ljava/lang/Deprecated;"; // #14 at 0x95 + Utf8 "forRemoval"; // #15 at 0xAE + int 0x00000001; // #16 at 0xBB + Utf8 "since"; // #17 at 0xC0 + Utf8 "now"; // #18 at 0xC8 + Utf8 "SourceFile"; // #19 at 0xCE + Utf8 "BadDeprecatedForRemovalBadCPIndex.java"; // #20 at 0xDB + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // Fields + } // Fields + + [2] { // Methods + { // method at 0xFF + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0107 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x011E + [1] { // line_number_table + 0 1; // at 0x012A + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method at 0x012A + 0x0009; // access + #11; // name_index : m + #6; // descriptor_index : ()V + [3] { // Attributes + Attr(#9, 25) { // Code at 0x0132 + 0; // max_stack + 0; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0145 + [1] { // line_number_table + 0 4; // at 0x0151 + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#12, 0) { // Deprecated at 0x0151 + } // end Deprecated + ; + Attr(#13, 16) { // RuntimeVisibleAnnotations at 0x0157 + [1] { // annotations + { // annotation + #14; + [2] { // element_value_pairs + { // element value pair + #17; + { // element_value + 's'; + #18; + } // element_value + } // element value pair + ; + { // element value pair + #15; + { // element_value + 'Z'; + #1600; // Changed from #16 to #1600 + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#19, 2) { // SourceFile at 0x016F + #20; + } // end SourceFile + } // Attributes +} // end class BadDeprecatedForRemovalBadCPIndex diff --git a/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalWrongType.jcod b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalWrongType.jcod new file mode 100644 index 0000000000000..9a2a536d664e3 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedForRemovalWrongType.jcod @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/* Based on source: + * + * public class DeprecatedMethod { + * @Deprecated(forRemoval=true, since="now") + * public static void m() {} + * } + * + * We change the type of forRemoval from 'Z' to 's' but don't change the value + */ + +class BadDeprecatedForRemovalWrongType { + 0xCAFEBABE; + 0; // minor version + 65; // version + [21] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadDeprecatedForRemovalWrongType"; // #8 at 0x3C + Utf8 "Code"; // #9 at 0x4F + Utf8 "LineNumberTable"; // #10 at 0x56 + Utf8 "m"; // #11 at 0x68 + Utf8 "Deprecated"; // #12 at 0x6C + Utf8 "RuntimeVisibleAnnotations"; // #13 at 0x79 + Utf8 "Ljava/lang/Deprecated;"; // #14 at 0x95 + Utf8 "forRemoval"; // #15 at 0xAE + int 0x00000001; // #16 at 0xBB + Utf8 "since"; // #17 at 0xC0 + Utf8 "now"; // #18 at 0xC8 + Utf8 "SourceFile"; // #19 at 0xCE + Utf8 "BadDeprecatedForRemovalWrongType.java"; // #20 at 0xDB + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // Fields + } // Fields + + [2] { // Methods + { // method at 0xFF + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0107 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x011E + [1] { // line_number_table + 0 1; // at 0x012A + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method at 0x012A + 0x0009; // access + #11; // name_index : m + #6; // descriptor_index : ()V + [3] { // Attributes + Attr(#9, 25) { // Code at 0x0132 + 0; // max_stack + 0; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0145 + [1] { // line_number_table + 0 4; // at 0x0151 + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#12, 0) { // Deprecated at 0x0151 + } // end Deprecated + ; + Attr(#13, 16) { // RuntimeVisibleAnnotations at 0x0157 + [1] { // annotations + { // annotation + #14; + [2] { // element_value_pairs + { // element value pair + #17; + { // element_value + 's'; + #18; + } // element_value + } // element value pair + ; + { // element value pair + #15; + { // element_value + 's'; // Changed from Z to s + #16; + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#19, 2) { // SourceFile at 0x016F + #20; + } // end SourceFile + } // Attributes +} // end class BadDeprecatedForRemovalWrongType diff --git a/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedSinceWrongType.jcod b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedSinceWrongType.jcod new file mode 100644 index 0000000000000..85863ea3b86a1 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/BadDeprecatedSinceWrongType.jcod @@ -0,0 +1,155 @@ +/* + * 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. + */ + +/* Based on source: + * + * public class DeprecatedMethod { + * @Deprecated(forRemoval=true, since="now") + * public static void m() {} + * } + * + * We change the type of since from 's' to 'Z' + */ + +class BadDeprecatedSinceWrongType { + 0xCAFEBABE; + 0; // minor version + 65; // version + [21] { // Constant Pool + ; // first element is empty + Method #2 #3; // #1 at 0x0A + class #4; // #2 at 0x0F + NameAndType #5 #6; // #3 at 0x12 + Utf8 "java/lang/Object"; // #4 at 0x17 + Utf8 ""; // #5 at 0x2A + Utf8 "()V"; // #6 at 0x33 + class #8; // #7 at 0x39 + Utf8 "BadDeprecatedSinceWrongType"; // #8 at 0x3C + Utf8 "Code"; // #9 at 0x4F + Utf8 "LineNumberTable"; // #10 at 0x56 + Utf8 "m"; // #11 at 0x68 + Utf8 "Deprecated"; // #12 at 0x6C + Utf8 "RuntimeVisibleAnnotations"; // #13 at 0x79 + Utf8 "Ljava/lang/Deprecated;"; // #14 at 0x95 + Utf8 "forRemoval"; // #15 at 0xAE + int 0x00000001; // #16 at 0xBB + Utf8 "since"; // #17 at 0xC0 + Utf8 "now"; // #18 at 0xC8 + Utf8 "SourceFile"; // #19 at 0xCE + Utf8 "BadDeprecatedSinceWrongType.java"; // #20 at 0xDB + } // Constant Pool + + 0x0021; // access [ ACC_PUBLIC ACC_SUPER ] + #7;// this_cpx + #2;// super_cpx + + [0] { // Interfaces + } // Interfaces + + [0] { // Fields + } // Fields + + [2] { // Methods + { // method at 0xFF + 0x0001; // access + #5; // name_index : + #6; // descriptor_index : ()V + [1] { // Attributes + Attr(#9, 29) { // Code at 0x0107 + 1; // max_stack + 1; // max_locals + Bytes[5]{ + 0x2AB70001B1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x011E + [1] { // line_number_table + 0 1; // at 0x012A + } + } // end LineNumberTable + } // Attributes + } // end Code + } // Attributes + } + ; + { // method at 0x012A + 0x0009; // access + #11; // name_index : m + #6; // descriptor_index : ()V + [3] { // Attributes + Attr(#9, 25) { // Code at 0x0132 + 0; // max_stack + 0; // max_locals + Bytes[1]{ + 0xB1; + } + [0] { // Traps + } // end Traps + [1] { // Attributes + Attr(#10, 6) { // LineNumberTable at 0x0145 + [1] { // line_number_table + 0 4; // at 0x0151 + } + } // end LineNumberTable + } // Attributes + } // end Code + ; + Attr(#12, 0) { // Deprecated at 0x0151 + } // end Deprecated + ; + Attr(#13, 16) { // RuntimeVisibleAnnotations at 0x0157 + [1] { // annotations + { // annotation + #14; + [2] { // element_value_pairs + { // element value pair + #17; + { // element_value + 'Z'; // Changed from 's' to 'Z' + #18; + } // element_value + } // element value pair + ; + { // element value pair + #15; + { // element_value + 'Z'; + #16; + } // element_value + } // element value pair + } // element_value_pairs + } // annotation + } + } // end RuntimeVisibleAnnotations + } // Attributes + } + } // Methods + + [1] { // Attributes + Attr(#19, 2) { // SourceFile at 0x016F + #20; + } // end SourceFile + } // Attributes +} // end class BadDeprecatedSinceWrongType diff --git a/test/hotspot/jtreg/runtime/Annotations/TestBadAnnotations.java b/test/hotspot/jtreg/runtime/Annotations/TestBadAnnotations.java new file mode 100644 index 0000000000000..6617858d61bf2 --- /dev/null +++ b/test/hotspot/jtreg/runtime/Annotations/TestBadAnnotations.java @@ -0,0 +1,64 @@ +/* + * 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 + * @bug 8339192 + * @summary Check that malformed annotations don't cause crashes + * @compile BadDeprecatedExtraMemberAtEnd.jcod + * BadDeprecatedExtraMemberAtStart.jcod + * BadDeprecatedSinceWrongType.jcod + * BadDeprecatedForRemovalWrongType.jcod + * BadDeprecatedForRemovalBadCPIndex.jcod + * BadContendedGroupBadCPIndex.jcod + * BadContendedGroupWrongType.jcod + * @modules java.base/jdk.internal.vm.annotation + * @run main/othervm -XX:-RestrictContended TestBadAnnotations + */ +import java.lang.annotation.Annotation; +import java.lang.reflect.*; + +// None of the malformed nnotations should cause assertion failures or +// other crashes, nor exceptions - we simply don't process them. Note that +// even if the annotation is malformed the class will still be marked as having +// that annotation; it is only the "forRemoval" state of @Deprecated, and +// the "group" value of @Contended that is potentially afffected. +// There is no API to query what annotations the VM considers applied +// to a class/field/method, so we don't try to read anything back. + +// The testcases defined reflect the changes that were made to the code under +// 8339192 - we do not try to define exhaustive tests for every potential +// malformation. Each of these test case will trigger an assert prior to +// the fix. + +public class TestBadAnnotations { + public static void main(String[] args) throws Throwable { + Class c = Class.forName("BadDeprecatedExtraMemberAtEnd"); + c = Class.forName("BadDeprecatedExtraMemberAtStart"); + c = Class.forName("BadDeprecatedSinceWrongType"); + c = Class.forName("BadDeprecatedForRemovalWrongType"); + c = Class.forName("BadDeprecatedForRemovalBadCPIndex"); + c = Class.forName("BadContendedGroupBadCPIndex"); + c = Class.forName("BadContendedGroupWrongType"); + } +} diff --git a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java index f16e0ff9da4fd..d47a07d2decb2 100644 --- a/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java +++ b/test/hotspot/jtreg/runtime/Thread/TestAlwaysPreTouchStacks.java @@ -36,7 +36,7 @@ import static jdk.test.lib.Platform.isWindows; /* - * @test id=preTouch + * @test id=preTouchTest * @summary Test AlwaysPreTouchThreadStacks * @requires os.family != "aix" * @library /test/lib @@ -45,23 +45,16 @@ * @run driver TestAlwaysPreTouchStacks preTouch */ -/* - * @test id=noPreTouch - * @summary Test that only touched committed memory is reported as thread stack usage. - * @requires os.family != "aix" - * @library /test/lib - * @modules java.base/jdk.internal.misc - * java.management - * @run driver TestAlwaysPreTouchStacks noPreTouch - */ - public class TestAlwaysPreTouchStacks { // We will create a bunch of large-stacked threads to make a significant imprint on combined thread stack size - final static int MB = 1024*1024; + final static int MB = 1024 * 1024; static int memoryCeilingMB = 128; static int threadStackSizeMB = 8; static int numThreads = memoryCeilingMB / threadStackSizeMB; + static long min_stack_usage_with_pretouch = 1 * MB; + static long max_stack_usage_with_pretouch = (long)(0.75 * threadStackSizeMB * MB); + static CyclicBarrier gate = new CyclicBarrier(numThreads + 1); static private final Thread createTestThread(int num) { @@ -79,10 +72,76 @@ static private final Thread createTestThread(int num) { } }, "TestThread-" + num, threadStackSizeMB * MB); + // Let test threads run as daemons to ensure that they are still running and + // that their stacks are still allocated when the JVM shuts down and the final + // NMT report is printed. t.setDaemon(true); return t; } + private static long runPreTouchTest(boolean preTouch) throws Exception { + long reserved = 0L, committed = 0L; + ArrayList vmArgs = new ArrayList<>(); + Collections.addAll(vmArgs, + "-XX:+UnlockDiagnosticVMOptions", + "-Xmx100M", + "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics"); + if (preTouch){ + vmArgs.add("-XX:+AlwaysPreTouchStacks"); + } + if (System.getProperty("os.name").contains("Linux")) { + vmArgs.add("-XX:-UseMadvPopulateWrite"); + } + Collections.addAll(vmArgs, "TestAlwaysPreTouchStacks", "test"); + ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(vmArgs); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + for (int i = 0; i < numThreads; i++) { + output.shouldContain("Alive: " + i); + } + + // If using -XX:+AlwaysPreTouchStacks, we want to see, in the final NMT printout, + // a committed thread stack size very close to reserved stack size. Like this: + // - Thread (reserved=10332400KB, committed=10284360KB) + // (thread #10021) + // (stack: reserved=10301560KB, committed=10253520KB) <<<< + // + // ... without -XX:+AlwaysPreTouchStacks, the committed/reserved ratio for thread stacks should be + // a lot lower, e.g.: + // - Thread (reserved=10332400KB, committed=331828KB) + // (thread #10021) + // (stack: reserved=10301560KB, committed=300988KB) <<< + + output.shouldMatch("- *Thread.*reserved.*committed"); + output.reportDiagnosticSummary(); + Pattern pat = Pattern.compile(".*stack: reserved=(\\d+), committed=(\\d+).*"); + boolean foundLine = false; + for (String line : output.asLines()) { + Matcher m = pat.matcher(line); + if (m.matches()) { + reserved = Long.parseLong(m.group(1)); + committed = Long.parseLong(m.group(2)); + System.out.println(">>>>> " + line + ": " + reserved + " - " + committed); + // Added sanity tests: we expect our test threads to be still alive when NMT prints its final + // report, so their stacks should dominate the NMT-reported total stack size. + long max_reserved = memoryCeilingMB * 3 * MB; + long min_reserved = memoryCeilingMB * MB; + if (reserved >= max_reserved || reserved < min_reserved) { + throw new RuntimeException("Total reserved stack sizes outside of our expectations (" + reserved + + ", expected " + min_reserved + ".." + max_reserved + ")"); + } + foundLine = true; + break; + } + } + if (!foundLine) { + throw new RuntimeException("Did not find expected NMT output"); + } + return committed; + } + public static void main(String[] args) throws Exception { if (args.length == 1 && args[0].equals("test")) { @@ -103,83 +162,23 @@ public static void main(String[] args) throws Exception { // should show up with fully - or almost fully - committed thread stacks. } else { - boolean preTouch; - if (args.length == 1 && args[0].equals("noPreTouch")){ - preTouch = false; - } else if (args.length == 1 && args[0].equals("preTouch")){ - preTouch = true; - } else { - throw new RuntimeException("Invalid test input. Must be 'preTouch' or 'noPreTouch'."); - } - ArrayList vmArgs = new ArrayList<>(); - Collections.addAll(vmArgs, - "-XX:+UnlockDiagnosticVMOptions", - "-Xmx100M", - "-XX:NativeMemoryTracking=summary", "-XX:+PrintNMTStatistics"); - if (preTouch){ - vmArgs.add("-XX:+AlwaysPreTouchStacks"); - } - if (System.getProperty("os.name").contains("Linux")) { - vmArgs.add("-XX:-UseMadvPopulateWrite"); - } - Collections.addAll(vmArgs, "TestAlwaysPreTouchStacks", "test"); - ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder(vmArgs); - OutputAnalyzer output = new OutputAnalyzer(pb.start()); - output.reportDiagnosticSummary(); - - output.shouldHaveExitValue(0); - - for (int i = 0; i < numThreads; i++) { - output.shouldContain("Alive: " + i); - } - - // If using -XX:+AlwaysPreTouchStacks, we want to see, in the final NMT printout, - // a committed thread stack size very close to reserved stack size. Like this: - // - Thread (reserved=10332400KB, committed=10284360KB) - // (thread #10021) - // (stack: reserved=10301560KB, committed=10253520KB) <<<< - // - // ... without -XX:+AlwaysPreTouchStacks, the committed/reserved ratio for thread stacks should be - // a lot lower, e.g.: - // - Thread (reserved=10332400KB, committed=331828KB) - // (thread #10021) - // (stack: reserved=10301560KB, committed=300988KB) <<< - - output.shouldMatch("- *Thread.*reserved.*committed"); - Pattern pat = Pattern.compile(".*stack: reserved=(\\d+), committed=(\\d+).*"); - boolean foundLine = false; - for (String line : output.asLines()) { - Matcher m = pat.matcher(line); - if (m.matches()) { - long reserved = Long.parseLong(m.group(1)); - long committed = Long.parseLong(m.group(2)); - System.out.println(">>>>> " + line + ": " + reserved + " - " + committed); - // This is a bit fuzzy: even with PreTouch we don't commit the full range of what NMT counts - // as thread stack. But without pre-touching, the thread stacks would be committed to about 1/5th - // of their reserved size. Requiring them to be committed for over 3/4th shows that pretouch is - // really working. - if (preTouch && (double)committed < ((double)reserved * 0.75)) { - throw new RuntimeException("Expected a higher ratio between stack committed and reserved."); - } else if (!preTouch && (double)committed > ((double)reserved * 0.50)){ - throw new RuntimeException("Expected a lower ratio between stack committed and reserved."); - } - // Added sanity tests: we expect our test threads to be still alive when NMT prints its final - // report, so their stacks should dominate the NMT-reported total stack size. - long max_reserved = memoryCeilingMB * 3 * MB; - long min_reserved = memoryCeilingMB * MB; - if (reserved >= max_reserved || reserved < min_reserved) { - throw new RuntimeException("Total reserved stack sizes outside of our expectations (" + reserved + - ", expected " + min_reserved + ".." + max_reserved + ")"); - } - foundLine = true; - break; - } - } - if (!foundLine) { - throw new RuntimeException("Did not find expected NMT output"); - } - } - + long pretouch_committed = runPreTouchTest(true); + long no_pretouch_committed = runPreTouchTest(false); + if (pretouch_committed == 0 || no_pretouch_committed == 0) { + throw new RuntimeException("Could not run with PreTouch flag."); + } + long expected_delta = numThreads * (max_stack_usage_with_pretouch - min_stack_usage_with_pretouch); + long actual_delta = pretouch_committed - no_pretouch_committed; + if (pretouch_committed <= (no_pretouch_committed + expected_delta)) { + throw new RuntimeException("Expected a higher amount of committed with pretouch stacks" + + "PreTouch amount: " + pretouch_committed + + "NoPreTouch amount: " + (no_pretouch_committed + expected_delta)); + } + if (actual_delta < expected_delta) { + throw new RuntimeException("Expected a higher delta between stack committed of with and without pretouch." + + "Expected: " + expected_delta + " Actual: " + actual_delta); + } + } } } diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java index 86b2c8fd425a8..2ad257476d0fb 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/IncompatibleOptions.java @@ -108,9 +108,9 @@ public static void test(String[] args_ignored) throws Exception { testDump(1, "-XX:+UseZGC", "-XX:-UseCompressedOops", null, false); } - // incompatible GCs - testDump(2, "-XX:+UseParallelGC", "", GC_WARNING, false); - testDump(3, "-XX:+UseSerialGC", "", GC_WARNING, false); + // Dump heap objects with ParallelGC and SerialGC + testDump(2, "-XX:+UseParallelGC", "", "", false); + testDump(3, "-XX:+UseSerialGC", "", "", false); // Explicitly archive with compressed oops, run without. testDump(5, "-XX:+UseG1GC", "-XX:+UseCompressedOops", null, false); diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java index 01cebb29f9138..3e2145c782188 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsHumongous.java @@ -27,6 +27,7 @@ * @summary Use a shared string allocated in a humongous G1 region. * @comment -- the following implies that G1 is used (by command-line or by default) * @requires vm.cds.write.archived.java.heap + * @requires vm.gc.G1 * * @library /test/hotspot/jtreg/runtime/cds/appcds /test/lib * @build HelloString diff --git a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsUtils.java b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsUtils.java index 57e39b5177aaa..4026f1d4f8414 100644 --- a/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsUtils.java +++ b/test/hotspot/jtreg/runtime/cds/appcds/sharedStrings/SharedStringsUtils.java @@ -96,7 +96,7 @@ public static OutputAnalyzer dumpWithoutChecks(String appClasses[], String appJar = TestCommon.getTestJar(TEST_JAR_NAME_FULL); String[] args = - TestCommon.concat(extraOptions, "-XX:+UseCompressedOops", "-XX:+UseG1GC", + TestCommon.concat(extraOptions, "-XX:+UseCompressedOops", "-XX:SharedArchiveConfigFile=" + TestCommon.getSourceFile(sharedDataFile)); args = TestCommon.concat(childVMOptionsPrefix, args); @@ -124,7 +124,7 @@ public static OutputAnalyzer runWithArchiveAuto(String className, String appJar = TestCommon.getTestJar(TEST_JAR_NAME_FULL); String[] args = TestCommon.concat(extraOptions, - "-cp", appJar, "-XX:+UseCompressedOops", "-XX:+UseG1GC", className); + "-cp", appJar, "-XX:+UseCompressedOops", className); args = TestCommon.concat(childVMOptionsPrefix, args); OutputAnalyzer output = TestCommon.execAuto(args); @@ -143,7 +143,7 @@ public static OutputAnalyzer runWithArchive(String[] extraMatches, String appJar = TestCommon.getTestJar(TEST_JAR_NAME_FULL); String[] args = TestCommon.concat(extraOptions, - "-XX:+UseCompressedOops", "-XX:+UseG1GC", className); + "-XX:+UseCompressedOops", className); args = TestCommon.concat(childVMOptionsPrefix, args); OutputAnalyzer output = TestCommon.exec(appJar, args); diff --git a/test/jdk/ProblemList.txt b/test/jdk/ProblemList.txt index 5c5f2d2fc6567..8060792a51f9a 100644 --- a/test/jdk/ProblemList.txt +++ b/test/jdk/ProblemList.txt @@ -136,6 +136,7 @@ java/awt/Focus/WrongKeyTypedConsumedTest/WrongKeyTypedConsumedTest.java 8169096 java/awt/Focus/TestDisabledAutoTransfer.java 8159871 macosx-all,windows-all java/awt/Focus/TestDisabledAutoTransferSwing.java 6962362 windows-all java/awt/Focus/ActivateOnProperAppContextTest.java 8136516 macosx-all +java/awt/Focus/FocusPolicyTest.java 7160904 linux-all java/awt/EventQueue/6980209/bug6980209.java 8198615 macosx-all java/awt/grab/EmbeddedFrameTest1/EmbeddedFrameTest1.java 7080150 macosx-all java/awt/event/InputEvent/EventWhenTest/EventWhenTest.java 8168646 generic-all @@ -515,6 +516,8 @@ java/io/pathNames/GeneralWin32.java 8180264 windows- com/sun/management/OperatingSystemMXBean/GetProcessCpuLoad.java 8030957 aix-all com/sun/management/OperatingSystemMXBean/GetSystemCpuLoad.java 8030957 aix-all +com/sun/management/DiagnosticCommandMBean/DcmdMBeanPermissionsTest.java 8340401 windows-all + java/lang/management/MemoryMXBean/Pending.java 8158837 generic-all java/lang/management/MemoryMXBean/PendingAllGC.sh 8158837 generic-all @@ -560,14 +563,19 @@ java/net/Socket/asyncClose/Race.java 8317801 aix-ppc6 # jdk_nio +java/nio/Buffer/LimitDirectMemory.java 8340728 generic-all + java/nio/channels/AsynchronousSocketChannel/StressLoopback.java 8211851 aix-ppc64 java/nio/channels/Channels/SocketChannelStreams.java 8317838 aix-ppc64 -java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807 aix-ppc64 +java/nio/channels/DatagramChannel/AdaptorMulticasting.java 8308807,8144003 aix-ppc64,macosx-all java/nio/channels/DatagramChannel/AfterDisconnect.java 8308807 aix-ppc64 java/nio/channels/DatagramChannel/ManySourcesAndTargets.java 8264385 macosx-aarch64 java/nio/channels/DatagramChannel/Unref.java 8233437 generic-all +java/nio/channels/DatagramChannel/BasicMulticastTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/MulticastSendReceiveTests.java 8144003 macosx-all +java/nio/channels/DatagramChannel/Promiscuous.java 8144003 macosx-all ############################################################################ @@ -788,3 +796,4 @@ java/awt/Focus/FrameMinimizeTest/FrameMinimizeTest.java 8016266 linux-x64 java/awt/Frame/SizeMinimizedTest.java 8305915 linux-x64 java/awt/PopupMenu/PopupHangTest.java 8340022 windows-all java/awt/Focus/MinimizeNonfocusableWindowTest.java 8024487 windows-all +java/awt/Focus/InactiveFocusRace.java 8023263 linux-all diff --git a/test/jdk/java/awt/Choice/CheckChoiceTest.java b/test/jdk/java/awt/Choice/CheckChoiceTest.java new file mode 100644 index 0000000000000..3e2e06b1c9557 --- /dev/null +++ b/test/jdk/java/awt/Choice/CheckChoiceTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1999, 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.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; +import javax.swing.JComponent; +import javax.swing.JPanel; +import javax.swing.SwingUtilities; + +/* + * @test + * @bug 4151949 + * @summary Verifies that Components are reshaped to their preferred size + * when their Container is packed. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CheckChoiceTest + */ + +public class CheckChoiceTest { + + private static JComponent componentToFocus; + + private static final String INSTRUCTIONS = """ + Verify that the widths of the Choice components are all the same + and that none is the minimum possible size. + (The Choices should be at least as wide as the Frame.) + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("CheckChoiceTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(45) + .testUI(CheckChoiceTest::createAndShowUI) + .splitUIBottom(CheckChoiceTest::createComponentToFocus) + .build(); + + // focus away from the window with choices + Thread.sleep(300); + SwingUtilities.invokeAndWait(() -> componentToFocus.requestFocus()); + + passFailJFrame.awaitAndCheck(); + } + + private static JComponent createComponentToFocus() { + componentToFocus = new JPanel(); + return componentToFocus; + } + + private static Frame createAndShowUI() { + Frame f = new Frame("Check Choice"); + f.setLayout(new BorderLayout()); + + Choice choice1 = new Choice(); + Choice choice2 = new Choice(); + Choice choice3 = new Choice(); + + f.add(choice1, BorderLayout.NORTH); + f.add(choice3, BorderLayout.CENTER); + f.add(choice2, BorderLayout.SOUTH); + f.pack(); + + choice1.add("I am Choice, yes I am : 0"); + choice2.add("I am the same, yes I am : 0"); + choice3.add("I am the same, yes I am : 0"); + + return f; + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceBigTest.java b/test/jdk/java/awt/Choice/ChoiceBigTest.java new file mode 100644 index 0000000000000..be82ed2a40db1 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceBigTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2001, 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.Choice; +import java.awt.Frame; +import java.awt.FlowLayout; +import java.awt.Window; + +/* + * @test + * @bug 4288285 + * @summary Verifies choice works with many items + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceBigTest + */ + +public class ChoiceBigTest { + private static final String INSTRUCTIONS = """ + Click the Choice button, press Pass if: + + - all looks good. + - if you can select the item 1000 + + Otherwise press Fail. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ChoiceBigTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(45) + .testUI(ChoiceBigTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowUI() { + Frame frame = new Frame("Check Choice"); + frame.setLayout(new FlowLayout()); + Choice choice = new Choice(); + frame.setSize(400, 200); + for (int i = 1; i < 1001; ++i) { + choice.add("I am Choice, yes I am : " + i); + } + frame.add(choice); + return frame; + } +} diff --git a/test/jdk/java/awt/Choice/ChoiceFocusTest.java b/test/jdk/java/awt/Choice/ChoiceFocusTest.java new file mode 100644 index 0000000000000..3ca895f88e6e9 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoiceFocusTest.java @@ -0,0 +1,81 @@ +/* + * 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.Choice; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Window; + +/* + * @test + * @bug 4927930 + * @summary Verify that the focus is set to the selected item after calling the java.awt.Choice.select() method + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ChoiceFocusTest + */ + +public class ChoiceFocusTest { + + private static final String INSTRUCTIONS = """ + 1. Use the mouse to select Item 5 in the Choice list. + 2. Click on the Choice. Item5 is now selected and highlighted. This is the correct behavior. + 3. Select Item 1 in the Choice list. + 4. Click the "choice.select(5)" button. This causes a call to Choice.select(5). Item 5 is now selected. + 5. Click on the Choice. + 6. If the cursor and focus are on item 5, the test passes. Otherwise, it fails. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ChoiceFocusTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(50) + .testUI(ChoiceFocusTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowUI() { + Panel panel = new Panel(); + Choice choice = new Choice(); + Button button = new Button("choice.select(5);"); + + for (int i = 0; i < 10; i++) { + choice.add(String.valueOf(i)); + } + + button.addActionListener(e -> choice.select(5)); + + panel.add(button); + panel.add(choice); + + Frame frame = new Frame("ChoiceFocusTest"); + frame.add(panel); + frame.pack(); + + return frame; + } +} diff --git a/test/jdk/java/awt/Choice/ChoicePosTest.java b/test/jdk/java/awt/Choice/ChoicePosTest.java new file mode 100644 index 0000000000000..c585e4709bbe5 --- /dev/null +++ b/test/jdk/java/awt/Choice/ChoicePosTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1999, 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.Choice; +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +/* + * @test + * @bug 4075194 + * @summary 4075194, Choice may not be displayed at the location requested + * @key headful + */ + +public class ChoicePosTest { + + private static Robot robot; + private static Frame frame; + private static final int GAP = 10; + private static volatile Choice c1,c2; + + public static void main(String[] args) throws Exception { + try { + EventQueue.invokeAndWait(ChoicePosTest::createAndShowGUI); + + robot = new Robot(); + robot.waitForIdle(); + robot.delay(500); + + captureAndTestChoices(); + } finally { + EventQueue.invokeAndWait(frame::dispose); + } + + System.out.println("Passed"); + } + + private static void createAndShowGUI() { + frame = new Frame("ChoicePosTest"); + Insets insets = frame.getInsets(); + frame.setSize( insets.left + 400 + insets.right, insets.top + 400 + insets.bottom ); + frame.setBackground(Color.RED); + frame.setLayout(null); + frame.setLocationRelativeTo(null); + + c1 = new Choice(); + c1.setBackground(Color.GREEN); + frame.add( c1 ); + c1.setBounds( 20, 50, 100, 100 ); + + c2 = new Choice(); + c2.setBackground(Color.GREEN); + frame.add(c2); + c2.addItem("One"); + c2.addItem("Two"); + c2.addItem("Three"); + c2.setBounds( 125, 50, 100, 100 ); + + frame.validate(); + frame.setVisible(true); + } + + private static void captureAndTestChoices() { + Point c1loc = c1.getLocationOnScreen(); + Point c2loc = c2.getLocationOnScreen(); + + int startX = c1loc.x - GAP; + int startY = c1loc.y - GAP; + int captureWidth = c2loc.x + c2.getWidth() + GAP - startX; + int captureHeight = c2loc.y + c2.getHeight() + GAP - startY; + + BufferedImage bi = robot.createScreenCapture( + new Rectangle(startX, startY, captureWidth, captureHeight) + ); + + int redPix = Color.RED.getRGB(); + + int lastNonRedCount = 0; + + for (int y = 0; y < captureHeight; y++) { + int nonRedCount = 0; + for (int x = 0; x < captureWidth; x++) { + int pix = bi.getRGB(x, y); + if (pix != redPix) { + nonRedCount++; + } + } + + if (nonRedCount > 0 && lastNonRedCount > 0) { + if (lastNonRedCount - nonRedCount > 0) { + System.err.printf( + "Failed at %d, nonRedCount: %d lastNonRedCount: %d\n", + y, nonRedCount, lastNonRedCount + ); + + try { + ImageIO.write(bi, "png", new File("choices.png")); + } catch (IOException ignored) { + } + + throw new RuntimeException("Choices are not aligned"); + } + } + + lastNonRedCount = nonRedCount; + } + } +} diff --git a/test/jdk/java/awt/Choice/DeadlockTest.java b/test/jdk/java/awt/Choice/DeadlockTest.java new file mode 100644 index 0000000000000..fdc6d94e6ba81 --- /dev/null +++ b/test/jdk/java/awt/Choice/DeadlockTest.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1998, 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.BorderLayout; +import java.awt.Choice; +import java.awt.Frame; +import jdk.test.lib.Platform; + +/* + * @test + * @bug 4134619 + * @summary Tests that the EventDispatchThread doesn't deadlock with + * user threads which are modifying a Choice component. + * @library /java/awt/regtesthelpers /test/lib + * @build PassFailJFrame jdk.test.lib.Platform + * @run main/manual DeadlockTest + */ + +public class DeadlockTest extends Thread { + + static volatile Choice choice1; + static volatile Choice choice2; + static volatile Choice choice3; + static volatile Frame frame; + static int itemCount = 0; + + private static final boolean isWindows = Platform.isWindows(); + + private static final String INSTRUCTIONS = """ + Click on the top Choice component and hold the mouse still briefly. + Then, without releasing the mouse button, move the cursor to a menu + item and then again hold the mouse still briefly. + %s + Release the button and repeat this process. + + Verify that this does not cause a deadlock + or crash within a reasonable amount of time. + """.formatted( + isWindows + ? "(menu can automatically collapse sometimes, this is ok)\n" + : "" + + ) ; + + public static void main(String[] args) throws Exception { + DeadlockTest deadlockTest = new DeadlockTest(); + PassFailJFrame passFailJFrame = PassFailJFrame.builder() + .title("DeadlockTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(deadlockTest::createAndShowUI) + .build(); + + deadlockTest.start(); + + passFailJFrame.awaitAndCheck(); + } + + public Frame createAndShowUI() { + frame = new Frame("Check Choice"); + frame.setLayout(new BorderLayout()); + choice1 = new Choice(); + choice2 = new Choice(); + choice3 = new Choice(); + frame.add(choice1, BorderLayout.NORTH); + frame.add(choice3, BorderLayout.CENTER); + frame.add(choice2, BorderLayout.SOUTH); + frame.pack(); + return frame; + } + + public void run() { + while (true) { + if (choice1 != null && itemCount < 40) { + choice1.add("I am Choice, yes I am : " + itemCount * itemCount); + choice2.add("I am the same, yes I am : " + itemCount * itemCount); + choice3.add("I am the same, yes I am : " + itemCount * itemCount); + itemCount++; + } + if (itemCount >= 20 && choice1 != null && + choice1.getItemCount() > 0) { + choice1.removeAll(); + choice2.removeAll(); + choice3.removeAll(); + itemCount = 0; + } + frame.validate(); + try { + Thread.sleep(1000); + } catch (Exception ignored) {} + } + } +} diff --git a/test/jdk/java/awt/Choice/DisabledList.java b/test/jdk/java/awt/Choice/DisabledList.java new file mode 100644 index 0000000000000..d028527303f7a --- /dev/null +++ b/test/jdk/java/awt/Choice/DisabledList.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011, 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.BorderLayout; +import java.awt.Checkbox; +import java.awt.Choice; +import java.awt.Frame; +import java.awt.Window; +import java.awt.event.ItemEvent; + +/* + * @test + * @bug 6476183 + * @summary Drop down of a Choice changed to enabled state has a disabled like appearance + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DisabledList + */ + +public class DisabledList { + + private static final String INSTRUCTIONS = """ + 1) Select the checkbox + 2) Open Choice + 3) Drag mouse over the scrollbar or drag out it the choice + 4) If choice's items become disabled press fail, otherwise pass + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DisabledList Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 3) + .columns(45) + .testUI(DisabledList::createAndShowUI) + .logArea(4) + .build() + .awaitAndCheck(); + } + + private static Window createAndShowUI() { + Frame frame = new Frame("DisabledList"); + frame.setSize(200, 200); + frame.validate(); + Checkbox checkbox = new Checkbox("checkbox"); + final Choice choice = new Choice(); + choice.setEnabled(false); + for (int i = 0; i < 15; i++) { + choice.addItem("Item" + i); + } + checkbox.addItemListener(event -> { + PassFailJFrame.log("CheckBox.itemStateChanged occurred"); + choice.setEnabled(event.getStateChange() == ItemEvent.SELECTED); + }); + frame.add(BorderLayout.NORTH, checkbox); + frame.add(BorderLayout.CENTER, choice); + return frame; + } +} diff --git a/test/jdk/java/awt/Choice/SetFontTest.java b/test/jdk/java/awt/Choice/SetFontTest.java new file mode 100644 index 0000000000000..f38a34a7ed278 --- /dev/null +++ b/test/jdk/java/awt/Choice/SetFontTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1999, 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.BorderLayout; +import java.awt.Choice; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Panel; + +/* + * @test + * @bug 4293346 + * @summary Checks that Choice does update its dimensions on font change + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetFontTest + */ + +public class SetFontTest { + + private static final String INSTRUCTIONS = """ + Choice component used to not update its dimension on font change. + Select one of fonts on the choice pull down list. + Pull down the list after the font change; if items in the list are + shown correctly the test is passed, otherwise it failed. + """; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("SetFontTest Instructions") + .instructions(INSTRUCTIONS) + .columns(45) + .testUI(SetFontTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("SetFontTest"); + Choice choice = new Choice(); + frame.setBounds(100, 400, 400, 100); + choice.addItem("dummy"); + choice.addItem("Set LARGE Font"); + choice.addItem("Set small Font"); + choice.addItem("addNewItem"); + choice.addItem("deleteItem"); + + choice.addItemListener(e -> { + if (e.getItem().toString().equals("addNewItem")) { + choice.addItem("very very very very long item"); + frame.validate(); + } else if (e.getItem().toString().equals("deleteItem")) { + if (choice.getItemCount() > 4) { + choice.remove(4); + frame.validate(); + } + } else if (e.getItem().toString().equals("Set LARGE Font")) { + choice.setFont(new Font("Dialog", Font.PLAIN, 24)); + frame.validate(); + } else if (e.getItem().toString().equals("Set small Font")) { + choice.setFont(new Font("Dialog", Font.PLAIN, 10)); + frame.validate(); + } + }); + Panel panel = new Panel(); + panel.add(choice); + frame.add(panel, BorderLayout.CENTER); + return frame; + } +} diff --git a/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java new file mode 100644 index 0000000000000..3f161f7fcaf90 --- /dev/null +++ b/test/jdk/java/awt/Desktop/EditAndPrintTest/EditAndPrintTest.java @@ -0,0 +1,152 @@ +/* + * 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. + */ + +/* + * @test + * @key printer + * @bug 6255196 + * @summary Verifies the function of methods edit(java.io.File file) and + * print(java.io.File file) + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual EditAndPrintTest + */ + +import java.awt.Desktop; +import java.awt.Desktop.Action; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import javax.swing.JPanel; + +public class EditAndPrintTest extends JPanel { + + static final String INSTRUCTIONS = """ + This test tries to edit and print a directory, which will expectedly raise IOException. + Then this test would edit and print a .txt file, which should be successful. + After test execution close the editor if it was launched by test. + If you see any EXCEPTION messages in the output press FAIL. + """; + + public EditAndPrintTest() { + if (!Desktop.isDesktopSupported()) { + PassFailJFrame.log("Class java.awt.Desktop is not supported on " + + "current platform. Further testing will not be performed"); + PassFailJFrame.forcePass(); + } + + Desktop desktop = Desktop.getDesktop(); + + if (!desktop.isSupported(Action.PRINT) && !desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Neither EDIT nor PRINT actions are supported. Nothing to test."); + PassFailJFrame.forcePass(); + } + + /* + * Part 1: print or edit a directory, which should throw an IOException. + */ + File userHome = new File(System.getProperty("user.home")); + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Trying to edit " + userHome); + desktop.edit(userHome); + PassFailJFrame.log("No exception has been thrown for editing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action EDIT is unsupported."); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + userHome); + desktop.print(userHome); + PassFailJFrame.log("No exception has been thrown for printing " + + "directory " + userHome.getPath()); + PassFailJFrame.log("Test failed."); + } else { + PassFailJFrame.log("Action PRINT is unsupported.\n"); + } + } catch (IOException e) { + PassFailJFrame.log("Expected IOException is caught."); + } + + /* + * Part 2: print or edit a normal .txt file, which may succeed if there + * is associated application to print or edit the given file. It fails + * otherwise. + */ + // Create a temp .txt file for test. + String testFilePath = System.getProperty("java.io.tmpdir") + File.separator + "JDIC-test.txt"; + File testFile = null; + try { + PassFailJFrame.log("Creating temporary file."); + testFile = File.createTempFile("JDIC-test", ".txt", new File(System.getProperty("java.io.tmpdir"))); + testFile.deleteOnExit(); + FileWriter writer = new FileWriter(testFile); + writer.write("This is a temp file used to test print() method of Desktop."); + writer.flush(); + writer.close(); + } catch (java.io.IOException ioe){ + PassFailJFrame.log("EXCEPTION: " + ioe.getMessage()); + PassFailJFrame.forceFail("Failed to create temp file for testing."); + } + + try { + if (desktop.isSupported(Action.EDIT)) { + PassFailJFrame.log("Try to edit " + testFile); + desktop.edit(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + + try { + if (desktop.isSupported(Action.PRINT)) { + PassFailJFrame.log("Trying to print " + testFile); + desktop.print(testFile); + PassFailJFrame.log("Succeed."); + } + } catch (IOException e) { + PassFailJFrame.log("EXCEPTION: " + e.getMessage()); + } + } + + public static void main(String args[]) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Edit and Print test") + .splitUI(EditAndPrintTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(60) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/Focus/ActivateFocusTest.java b/test/jdk/java/awt/Focus/ActivateFocusTest.java new file mode 100644 index 0000000000000..09f5bbb172ca8 --- /dev/null +++ b/test/jdk/java/awt/Focus/ActivateFocusTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2001, 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 + * @bug 4369903 + * @summary Focus on window activation does not work correctly + * @key headful + * @run main ActivateFocusTest + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Toolkit; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class ActivateFocusTest { + + public static void main(final String[] args) { + ActivateFocusTest app = new ActivateFocusTest(); + app.doTest(); + } + + public void doTest() { + ActivateFocus[] af = new ActivateFocus[2]; + boolean testFailed = false; + Dimension scrSize = Toolkit.getDefaultToolkit().getScreenSize(); + for (int i = 0; i < 2; i++) { + af[i] = new ActivateFocus(i); + af[i].setLocation(i * 160 + scrSize.width / 2, scrSize.height / 2); + af[i].setVisible(true); + } + try { + Thread.sleep(5000); + } catch (InterruptedException ie) { + throw new RuntimeException("TEST FAILED - thread was interrupted"); + } + for (int i = 0; i < 2; i++) { + testFailed = (af[i].lw.focusCounter > 1); + } + if (testFailed) { + throw new RuntimeException("TEST FAILED - focus is gained more than one time"); + } else { + System.out.println("TEST PASSED"); + } + } + + } + +class ActivateFocus extends Frame { + + public LightWeight lw = null; + int num; + + public String toString() { + return ("Window " + num); + } + + public ActivateFocus(int i) { + setTitle("Window " + i); + lw = new LightWeight(i); + num=i; + addWindowListener(new WindowAdapter() { + public void windowActivated(WindowEvent e) { + if(lw != null) { + lw.requestFocus(); + } + } + }); + add(lw); + pack(); + } + + // A very simple lightweight component + class LightWeight extends Component implements FocusListener { + + boolean focused = false; + int num; + public int focusCounter = 0; + + public LightWeight(int num) { + this.num = num; + addFocusListener(this); + } + + public void paint(Graphics g) { + Dimension size = getSize(); + int w = size.width; + int h = size.height; + g.setColor(getBackground()); + g.fillRect(0, 0, w, h); + g.setColor(Color.black); + g.drawOval(0, 0, w-1, h-1); + if (focused) { + g.drawLine(w/2, 0, w/2, h); + g.drawLine(0, h/2, w, h/2); + } + + } + + public Dimension getPreferredSize() { + return new Dimension(150, 150); + } + + public void focusGained(FocusEvent e) { + focused = true; + focusCounter++; + System.out.println("focusGained on " + e.getComponent()); + repaint(); + } + + public void focusLost(FocusEvent e) { + focused = false; + System.out.println("focusLost on " + e.getComponent()); + repaint(); + } + + public String toString() { + return ("Component " + num); + } + } +} diff --git a/test/jdk/java/awt/Focus/AltTabEventsTest.java b/test/jdk/java/awt/Focus/AltTabEventsTest.java new file mode 100644 index 0000000000000..15d679ce7295a --- /dev/null +++ b/test/jdk/java/awt/Focus/AltTabEventsTest.java @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2002, 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 + * @bug 4524015 + * @summary Tests that when user switches between windows using Alt-tab then the appropriate events are generated + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual AltTabEventsTest + */ + +import java.awt.Button; +import java.awt.Choice; +import java.awt.Component; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.event.ActionListener; +import java.awt.event.ActionEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class AltTabEventsTest { + + private static final String INSTRUCTIONS = """ + This test verifies that when user switches between windows using Alt-tab + key combination then appropriate window events are generated. Also, when + user interacts with Menu bar, Popup menu, Choice then no excessive window + event is generated. + + After test started you will see Frame('Test for 4524015')-F1 with some + components and Frame('Another frame')-F2 with no components. + 1. Make F1 active by clicking on it. + 2. Press Alt-tab. + In the messqge dialog area you should see that + WINDOW_DEACTIVATED, WINDOW_LOST_FOCUS event were generated. + If you switched to F2 then also WINDOW_ACTIVATED, WINDOW_GAINED_FOCUS + were generated. + If no events were generated the test FAILED. + Repeat the 2) with different circumstances. + + 3. Make F1 active by clicking on it. + 4. Click on Menu bar/Button 'popup'/Choice and select some item from + the list shown. If any of the window events appeared in the output then + the test FAILED. + + else the test PASSED."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("AltTabEventsTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 5) + .columns(35) + .testUI(Test::new) + .logArea() + .build() + .awaitAndCheck(); + } + +} + + +class Test extends Frame { + PopupMenu pop; + Frame f; + + void println(String messageIn) { + PassFailJFrame.log(messageIn); + } + + public Test() { + super("Test for 4524015"); + WindowAdapter wa = new WindowAdapter() { + public void windowActivated(WindowEvent e) { + println(e.toString()); + } + public void windowDeactivated(WindowEvent e) { + println(e.toString()); + } + public void windowGainedFocus(WindowEvent e) { + println(e.toString()); + } + public void windowLostFocus(WindowEvent e) { + println(e.toString()); + } + }; + addWindowListener(wa); + addWindowFocusListener(wa); + + f = new Frame("Another frame"); + f.addWindowListener(wa); + f.addWindowFocusListener(wa); + f.setBounds(800, 300, 300, 100); + f.setVisible(true); + + setLayout(new FlowLayout()); + Button b = new Button("popup"); + add(b); + b.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + pop.show((Component)e.getSource(), 10, 10); + } + }); + Choice cho = new Choice(); + add(cho); + cho.addItem("1"); + cho.addItem("2"); + cho.addItem("3"); + + MenuBar bar = new MenuBar(); + Menu menu = new Menu("menu"); + MenuItem item = new MenuItem("first"); + menu.add(item); + item = new MenuItem("second"); + menu.add(item); + bar.add(menu); + setMenuBar(bar); + + pop = new PopupMenu(); + pop.add("1"); + pop.add("@"); + add(pop); + setSize(300, 100); + } +} + diff --git a/test/jdk/java/awt/Focus/CanvasPanelFocusOnClickTest.java b/test/jdk/java/awt/Focus/CanvasPanelFocusOnClickTest.java new file mode 100644 index 0000000000000..8df21ba0f0a67 --- /dev/null +++ b/test/jdk/java/awt/Focus/CanvasPanelFocusOnClickTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4041703 4096228 4032657 4066152 4149866 4025223 + * @summary Ensures that an Panel/Canvas without heavyweight children + receives focus on mouse click + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CanvasPanelFocusOnClickTest + */ + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Component; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +public class CanvasPanelFocusOnClickTest { + + private static final String INSTRUCTIONS = """ + + Click on the red Canvas. Verify that it has focus by key pressing. + Click on the yellow Panel. Verify that it has focus by key pressing. + Click on the blue heavyweight Panel (NOT ON THE BUTTON!). + Verify that it doesn't have focus by key pressing. + If two empty containers are able to the get focus by a mouse click + and the container with heavyweight children are unable to get + the focus by a mouse click which can be verified through messages in message dialog + the test passes."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("CanvasPanelFocusOnClickTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(CanvasPanelFocusOnClickTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Canvas canvas = new Canvas();; + Panel emptyPanel = new Panel(); + Panel panel = new Panel(); + Button buttonInPanel = new Button("BUTTON ON PANEL"); + + Frame frame = new Frame("CanvasPanelFocusOnClickTest Frame"); + frame.setLayout(new GridLayout(3, 1)); + canvas.setBackground(Color.red); + canvas.setName("RED CANVAS"); + canvas.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + println(e.toString()); + } + public void focusLost(FocusEvent e) { + println(e.toString()); + } + }); + canvas.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + printKey(e); + } + + public void keyTyped(KeyEvent e) { + printKey(e); + } + + public void keyReleased(KeyEvent e) { + printKey(e); + } + }); + frame.add(canvas); + + emptyPanel.setBackground(Color.yellow); + emptyPanel.setName("YELLOW PANEL"); + emptyPanel.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + println(e.toString()); + } + public void focusLost(FocusEvent e) { + println(e.toString()); + } + }); + emptyPanel.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + printKey(e); + } + + public void keyTyped(KeyEvent e) { + printKey(e); + } + + public void keyReleased(KeyEvent e) { + printKey(e); + } + }); + frame.add(emptyPanel); + + panel.setBackground(Color.blue); + panel.setName("BLUE PANEL"); + buttonInPanel.setName("BUTTON ON PANEL"); + buttonInPanel.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + println(e.toString()); + } + public void focusLost(FocusEvent e) { + println(e.toString()); + } + }); + buttonInPanel.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + printKey(e); + } + + public void keyTyped(KeyEvent e) { + printKey(e); + } + + public void keyReleased(KeyEvent e) { + printKey(e); + } + }); + panel.add(buttonInPanel); + panel.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + println(e.toString()); + } + public void focusLost(FocusEvent e) { + println(e.toString()); + } + }); + panel.addKeyListener(new KeyAdapter() { + public void keyPressed(KeyEvent e) { + printKey(e); + } + + public void keyTyped(KeyEvent e) { + printKey(e); + } + + public void keyReleased(KeyEvent e) { + printKey(e); + } + }); + frame.add(panel); + + frame.setSize(200, 200); + + return frame; + + } + + static void printKey(KeyEvent e) { + String typeStr; + switch(e.getID()) { + case KeyEvent.KEY_PRESSED: + typeStr = "KEY_PRESSED"; + break; + case KeyEvent.KEY_RELEASED: + typeStr = "KEY_RELEASED"; + break; + case KeyEvent.KEY_TYPED: + typeStr = "KEY_TYPED"; + break; + default: + typeStr = "unknown type"; + } + + Object source = e.getSource(); + if (source instanceof Component) { + typeStr += " on " + ((Component)source).getName(); + } else { + typeStr += " on " + source; + } + + println(typeStr); + } + + static void println(String messageIn) { + PassFailJFrame.log(messageIn); + } +} diff --git a/test/jdk/java/awt/Focus/ComponentLostFocusTest.java b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java new file mode 100644 index 0000000000000..6af8322b2cd82 --- /dev/null +++ b/test/jdk/java/awt/Focus/ComponentLostFocusTest.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2004, 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 + * @bug 4982943 + * @key headful + * @summary focus lost in text fields or text areas, unable to enter characters from keyboard + * @run main ComponentLostFocusTest + */ + +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.InputEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; + +public class ComponentLostFocusTest { + + static Frame frame; + static TextField tf; + static Robot r; + static Dialog dialog = null; + static volatile boolean passed; + static volatile Point loc; + static volatile int width; + static volatile int top; + + private static void createTestUI() { + + dialog = new Dialog(frame, "Dialog", true); + + frame = new Frame("ComponentLostFocusTest Frame"); + frame.setLayout(new FlowLayout()); + frame.addWindowFocusListener(new WindowAdapter() { + public void windowGainedFocus(WindowEvent e) { + System.out.println("Frame gained focus: "+e); + } + }); + tf = new TextField("Text Field"); + frame.add(tf); + frame.setSize(400,300); + frame.setVisible(true); + frame.setLocationRelativeTo(null); + frame.validate(); + } + + public static void doTest() { + System.out.println("dialog.setVisible.... "); + new Thread(new Runnable() { + public void run() { + dialog.setVisible(true); + } + }).start(); + + // The bug is that this construction leads to the redundant xRequestFocus + // By the way, the requestFocusInWindow() works fine before the fix + System.out.println("requesting.... "); + frame.requestFocus(); + + r.delay(1000); + + // Returning the focus to the initial frame will work correctly after the fix + System.out.println("disposing.... "); + dialog.dispose(); + + r.delay(1000); + + // We want to track the GAIN_FOCUS from this time + tf.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + System.out.println("TextField gained focus: " + e); + passed = true; + } + }); + + } + + private static void doRequestFocusToTextField() { + // do activation using press title + r.mouseMove(loc.x + width / 2, loc.y + top / 2); + r.waitForIdle(); + r.mousePress(InputEvent.BUTTON1_DOWN_MASK); + r.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + r.waitForIdle(); + + // request focus to the text field + tf.requestFocus(); + } + + public static final void main(String args[]) throws Exception { + r = new Robot(); + r.setAutoDelay(100); + + EventQueue.invokeAndWait(() -> createTestUI()); + r.waitForIdle(); + r.delay(1000); + try { + EventQueue.invokeAndWait(() -> { + doTest(); + loc = frame.getLocationOnScreen(); + width = frame.getWidth(); + top = frame.getInsets().top; + }); + doRequestFocusToTextField(); + + System.out.println("Focused window: " + + KeyboardFocusManager.getCurrentKeyboardFocusManager(). + getFocusedWindow()); + System.out.println("Focus owner: " + + KeyboardFocusManager.getCurrentKeyboardFocusManager(). + getFocusOwner()); + + if (!passed) { + throw new RuntimeException("TextField got no focus! Test failed."); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } +} + diff --git a/test/jdk/java/awt/Focus/ConsumedKeyEventTest.java b/test/jdk/java/awt/Focus/ConsumedKeyEventTest.java new file mode 100644 index 0000000000000..dda82adeec587 --- /dev/null +++ b/test/jdk/java/awt/Focus/ConsumedKeyEventTest.java @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2002, 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 + * @bug 4700276 + * @summary Peers process KeyEvents before KeyEventPostProcessors + * @requires (os.family == "windows") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ConsumedKeyEventTest +*/ + +import java.awt.Canvas; +import java.awt.Component; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.KeyboardFocusManager; +import java.awt.KeyEventPostProcessor; +import java.awt.event.KeyEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; +import java.awt.event.MouseAdapter; +import java.awt.event.MouseEvent; + +public class ConsumedKeyEventTest implements KeyEventPostProcessor { + + private static final String INSTRUCTIONS = """ + This is a Windows-only test. + When the test starts, you will see a Frame with two components in it, + components look like colored rectangles, one of them is lightweight, one is heavyweight. + Do the following: + 1. Click the mouse on the left component. + If it isn't yellow after the click (that means it doesn't have focus), the test fails. + 2. Press and release ALT key. + In the output window, the text should appear stating that those key events were consumed. + If no output appears, the test fails. + 3. Press space bar. If system menu drops down, the test fails. + 4. Click the right rectangle. + It should become red after the click. If it doesn't, it means that it didn't get the focus, and the test fails. + 5. Repeat steps 2. and 3. + 6. If the test didn't fail on any of the previous steps, the test passes."""; + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ConsumedKeyEventTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 5) + .columns(35) + .testUI(ConsumedKeyEventTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + KeyboardFocusManager.getCurrentKeyboardFocusManager(). + addKeyEventPostProcessor((e) -> { + System.out.println("postProcessor(" + e + ")"); + // consumes all ALT-events + if (e.getKeyCode() == KeyEvent.VK_ALT) { + println("consumed " + e); + e.consume(); + return true; + } + return false; + }); + FocusRequestor requestor = new FocusRequestor(); + Frame frame = new Frame("Main Frame"); + frame.setLayout(new FlowLayout()); + + Canvas canvas = new CustomCanvas(); + canvas.addMouseListener(requestor); + frame.add(canvas); + canvas.requestFocus(); + + Component lwComp = new LWComponent(); + lwComp.addMouseListener(requestor); + frame.add(lwComp); + + frame.pack(); + + return frame; + } + + public boolean postProcessKeyEvent(KeyEvent e) { + System.out.println("postProcessor(" + e + ")"); + // consumes all ALT-events + if (e.getKeyCode() == KeyEvent.VK_ALT) { + println("consumed " + e); + e.consume(); + return true; + } + return false; + } + + static void println(String messageIn) { + PassFailJFrame.log(messageIn); + } +}// class ConsumedKeyEventTest + +class CustomCanvas extends Canvas { + CustomCanvas() { + super(); + setName("HWComponent"); + setSize(100, 100); + addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent fe) { + repaint(); + } + + public void focusLost(FocusEvent fe) { + repaint(); + } + }); + } + + public void paint(Graphics g) { + if (isFocusOwner()) { + g.setColor(Color.YELLOW); + } else { + g.setColor(Color.GREEN); + } + g.fillRect(0, 0, 100, 100); + } + +} + +class LWComponent extends Component { + LWComponent() { + super(); + setName("LWComponent"); + addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent fe) { + repaint(); + } + + public void focusLost(FocusEvent fe) { + repaint(); + } + }); + } + + public Dimension getPreferredSize() { + return new Dimension(100, 100); + } + + public void paint(Graphics g) { + if (isFocusOwner()) { + g.setColor(Color.RED); + } else { + g.setColor(Color.BLACK); + } + g.fillRect(0, 0, 100, 100); + } + +} + +class FocusRequestor extends MouseAdapter { + static int counter = 0; + public void mouseClicked(MouseEvent me) { + System.out.println("mouseClicked on " + me.getComponent().getName()); + } + public void mousePressed(MouseEvent me) { + System.out.println("mousePressed on " + me.getComponent().getName()); + me.getComponent().requestFocus(); + } + public void mouseReleased(MouseEvent me) { + System.out.println("mouseReleased on " + me.getComponent().getName()); + } +} + diff --git a/test/jdk/java/awt/Focus/DeiconifyTest.java b/test/jdk/java/awt/Focus/DeiconifyTest.java new file mode 100644 index 0000000000000..e87b13b8e65fa --- /dev/null +++ b/test/jdk/java/awt/Focus/DeiconifyTest.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2000, 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 + * @bug 4380809 + * @summary Focus disappears after deiconifying frame + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual DeiconifyTest +*/ + +import java.awt.Button; +import java.awt.Frame; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; + +public class DeiconifyTest { + + private static final String INSTRUCTIONS = """ + 1. Activate frame \"Main frame\" + be sure that button has focus + 2. Minimize frame and then restore it. + If the button has focus then test passed, else failed"""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("DeiconifyTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(DeiconifyTest::createTestUI) + .logArea() + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame frame = new Frame("Main frame"); + Button button = new Button("button"); + button.addFocusListener(new FocusListener() { + public void focusGained(FocusEvent fe) { + println("focus gained"); + } + public void focusLost(FocusEvent fe) { + println("focus lost"); + } + }); + frame.add(button); + frame.setSize(300, 100); + + return frame; + } + + static void println(String messageIn) { + PassFailJFrame.log(messageIn); + } +} + diff --git a/test/jdk/java/awt/Focus/EmptyWindowKeyTest.java b/test/jdk/java/awt/Focus/EmptyWindowKeyTest.java new file mode 100644 index 0000000000000..bbdf8ce4f383b --- /dev/null +++ b/test/jdk/java/awt/Focus/EmptyWindowKeyTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001, 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 + * @bug 4464723 + * @summary Tests simple KeyAdapter / KeyListener on an empty, focusable window + * @key headful + * @run main EmptyWindowKeyTest +*/ + +import java.awt.AWTEvent; +import java.awt.Frame; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.Robot; + +public class EmptyWindowKeyTest { + + static volatile boolean passed1, passed2; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + MainFrame mainFrame = new MainFrame(); + mainFrame.setSize(50,50); + mainFrame.addKeyListener(new KeyboardTracker()); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + robot.waitForIdle(); + robot.delay(1000); + if (!passed1 || !passed2) { + throw new RuntimeException("KeyPress/keyRelease not seen," + + "passed1 " + passed1 + " passed2 " + passed2); + } + } + + static public class KeyboardTracker extends KeyAdapter { + public KeyboardTracker() { } + public void keyTyped(KeyEvent e) {} + + public void keyPressed(KeyEvent e) { + if (e.getKeyText(e.getKeyCode()).equals("A")) { + passed1 = true; + } + } + public void keyReleased(KeyEvent e) { + if (e.getKeyText(e.getKeyCode()).equals("A")) { + passed2 = true; + } + } + } + + static public class MainFrame extends Frame { + + public MainFrame() { + super(); + enableEvents(AWTEvent.KEY_EVENT_MASK); + setVisible(true); + } + + } + +} + diff --git a/test/jdk/java/awt/Focus/FocusKeepTest.java b/test/jdk/java/awt/Focus/FocusKeepTest.java new file mode 100644 index 0000000000000..0adc463f5d9ae --- /dev/null +++ b/test/jdk/java/awt/Focus/FocusKeepTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4128659 + * @summary Tests whether a focus request will work on a focus lost event. + * @key headful + * @run main FocusKeepTest + */ + +import java.awt.BorderLayout; +import java.awt.KeyboardFocusManager; +import java.awt.Robot; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import javax.swing.JFrame; +import javax.swing.JTextField; +import javax.swing.SwingUtilities; + +public class FocusKeepTest { + + static JFrame frame; + static JTextField tf; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + robot.setAutoDelay(100); + try { + SwingUtilities.invokeAndWait(() -> createTestUI()); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + if (KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() instanceof JTextField tf1) { + if (!tf1.getText().equals("TextField 1")) { + throw new RuntimeException("Focus on wrong textfield"); + } + } else { + throw new RuntimeException("Focus not on correct component"); + } + } finally { + SwingUtilities.invokeAndWait(() -> { + if (frame != null) { + frame.dispose(); + } + }); + } + } + + private static void createTestUI() { + frame = new JFrame("FocusKeepTest"); + tf = new JTextField("TextField 1"); + tf.addFocusListener(new MyFocusAdapter("TextField 1")); + frame.add(tf, BorderLayout.NORTH); + + tf = new JTextField("TextField 2"); + tf.addFocusListener(new MyFocusAdapter("TextField 2")); + frame.add(tf, BorderLayout.SOUTH); + + frame.pack(); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + } + + static class MyFocusAdapter extends FocusAdapter { + private String myName; + + public MyFocusAdapter (String name) { + myName = name; + } + + public void focusLost (FocusEvent e) { + if (myName.equals ("TextField 1")) { + e.getComponent().requestFocus (); + } + } + + public void focusGained (FocusEvent e) { + } + } +} diff --git a/test/jdk/java/awt/Focus/FocusPolicyTest.java b/test/jdk/java/awt/Focus/FocusPolicyTest.java new file mode 100644 index 0000000000000..3ec362acaf085 --- /dev/null +++ b/test/jdk/java/awt/Focus/FocusPolicyTest.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4897459 + * @key headful + * @summary The key does not switches focus in the internal frames in Swing apps. + * @run main FocusPolicyTest + */ + +import java.awt.Container; +import java.awt.Component; +import java.awt.DefaultFocusTraversalPolicy; +import java.awt.Dialog; +import java.awt.FocusTraversalPolicy; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Toolkit; +import java.awt.Window; +import javax.swing.JDialog; +import javax.swing.JInternalFrame; +import javax.swing.JFrame; +import javax.swing.JWindow; +import javax.swing.LayoutFocusTraversalPolicy; + +public class FocusPolicyTest { + static int stageNum; + static FocusTraversalPolicy customPolicy = new CustomPolicy(); + final static Class awtDefaultPolicy = DefaultFocusTraversalPolicy.class; + final static Class swingDefaultPolicy = LayoutFocusTraversalPolicy.class; + + public static void main(String[] args) { + final boolean isXawt = "sun.awt.X11.XToolkit".equals(Toolkit.getDefaultToolkit().getClass().getName()); + + System.err.println("isXawt = " + isXawt); + + // 1. Check default policy + if (KeyboardFocusManager.getCurrentKeyboardFocusManager(). + getDefaultFocusTraversalPolicy().getClass() != awtDefaultPolicy) { + throw new RuntimeException("Error: stage 1: default policy is not DefaultFocusTraversalPolicy"); + } + + // 2. Check AWT top-levels policies + stageNum = 2; + checkAWTPoliciesFor(awtDefaultPolicy); + + // 3. Check Swing top-levels policies + stageNum = 3; + checkSwingPoliciesFor(swingDefaultPolicy); + + // 4. Check default policy if not XToolkit + if (!isXawt) { + if (KeyboardFocusManager.getCurrentKeyboardFocusManager(). + getDefaultFocusTraversalPolicy().getClass() != swingDefaultPolicy) { + throw new RuntimeException("Error: stage 4: default policy is not LayoutFocusTraversalPolicy"); + } + } + + // 5. Check AWT top-levels policies + // this is a bug in XAWT we should change the test as soon as + // we will be able to fix this bug. + stageNum = 5; + Class defaultPolicy = swingDefaultPolicy; + if (isXawt) { + defaultPolicy = awtDefaultPolicy; + } + checkAWTPoliciesFor(defaultPolicy); + + // Set custom policy as default + KeyboardFocusManager.getCurrentKeyboardFocusManager().setDefaultFocusTraversalPolicy(customPolicy); + + // 6. Check AWT top-levels policies for custom + stageNum = 6; + checkAWTPoliciesFor(customPolicy.getClass()); + + // 7. Check Swing top-levels policies for custom + stageNum = 7; + checkSwingPoliciesFor(customPolicy.getClass()); + + return; + } + + public static void checkAWTPoliciesFor(Class expectedPolicyClass) { + Window[] tlvs = new Window[7]; + + tlvs[0] = new Frame(""); + tlvs[1] = new Frame("", tlvs[0].getGraphicsConfiguration()); + tlvs[2] = new Window((Frame)tlvs[0]); + tlvs[3] = new Dialog((Frame)tlvs[0], "", false); + tlvs[4] = new Dialog((Frame)tlvs[0], "", false, tlvs[0].getGraphicsConfiguration()); + tlvs[5] = new Dialog((Dialog)tlvs[3], "", false); + tlvs[6] = new Dialog((Dialog)tlvs[3], "", false, tlvs[0].getGraphicsConfiguration()); + + for (int i = 0; i < 7; i++) { + Class policyClass = tlvs[i].getFocusTraversalPolicy().getClass(); + if (policyClass != expectedPolicyClass) { + throw new RuntimeException("Error: stage " + stageNum + ": " + + tlvs[i].getClass().getName() + + "'s policy is " + policyClass.getName() + + " but not " + expectedPolicyClass.getName()); + } + } + } + + public static void checkSwingPoliciesFor(Class expectedPolicyClass) { + Container[] tlvs = new Container[12]; + + tlvs[0] = new JFrame(); + tlvs[1] = new JFrame(tlvs[0].getGraphicsConfiguration()); + tlvs[2] = new JFrame(""); + tlvs[3] = new JFrame("", tlvs[0].getGraphicsConfiguration()); + tlvs[4] = new JWindow((Frame)tlvs[0]); + tlvs[5] = new JWindow((Window)tlvs[4]); + tlvs[6] = new JWindow((Window)tlvs[4], tlvs[0].getGraphicsConfiguration()); + tlvs[7] = new JDialog((Frame)tlvs[0], "", false); + tlvs[8] = new JDialog((Frame)tlvs[0], "", false, tlvs[0].getGraphicsConfiguration()); + tlvs[9] = new JDialog((Dialog)tlvs[7], "", false); + tlvs[10] = new JDialog((Dialog)tlvs[7], "", false, tlvs[0].getGraphicsConfiguration()); + tlvs[11] = new JInternalFrame("", false, false, false, false); + + for (int i = 0; i < tlvs.length; i++) { + Class policyClass = tlvs[i].getFocusTraversalPolicy().getClass(); + if (policyClass != expectedPolicyClass) { + throw new RuntimeException("Error: stage " + stageNum + + ": " + tlvs[i].getClass().getName() + + "'s policy is " + policyClass.getName() + " but not " + + expectedPolicyClass.getName()); + } + } + } + + // Dummy policy. + static class CustomPolicy extends FocusTraversalPolicy { + public Component getComponentAfter(Container focusCycleRoot, + Component aComponent) { + return null; + } + + public Component getComponentBefore(Container focusCycleRoot, + Component aComponent) { + return null; + } + + public Component getFirstComponent(Container focusCycleRoot) { + return null; + } + + public Component getLastComponent(Container focusCycleRoot) { + return null; + } + + public Component getDefaultComponent(Container focusCycleRoot) { + return null; + } + } +} diff --git a/test/jdk/java/awt/Focus/HiddenTraversalTest.java b/test/jdk/java/awt/Focus/HiddenTraversalTest.java new file mode 100644 index 0000000000000..59e7f477945e5 --- /dev/null +++ b/test/jdk/java/awt/Focus/HiddenTraversalTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4157017 + * @summary Checks whether focus can be traversed when component not visible + within parent container. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual HiddenTraversalTest +*/ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Panel; + +public class HiddenTraversalTest { + + private static final String INSTRUCTIONS = """ + Examine the Frame. If six buttons are visible, resize the frame + so that only four are visible. If fewer than six buttons are + visible, do nothing.\n + Now, repeatedly press the tab key. Focus should cycle through the + visible and invisible buttons. If after six presses of the tab + button 'Button 0' has focus, the test passes. If focus is instead + stuck at 'Button 3', the test fails."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("HiddenTraversalTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(HiddenTraversalTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame f = new Frame("Focus test"); + Panel p = new Panel(new FlowLayout()); + for (int i = 0; i < 6; i++) { + p.add(new Button("Button " + i)); + } + f.add(p); + f.setSize(200, 100); + return f; + } + +} + diff --git a/test/jdk/java/awt/Focus/InactiveFocusRace.java b/test/jdk/java/awt/Focus/InactiveFocusRace.java new file mode 100644 index 0000000000000..efca2dbf53a13 --- /dev/null +++ b/test/jdk/java/awt/Focus/InactiveFocusRace.java @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2002, 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 + * @bug 4697451 + * @summary Test that there is no race between focus component in inactive window and window activation + * @key headful + * @run main InactiveFocusRace +*/ + +import java.awt.Button; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Robot; +import java.awt.Toolkit; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.awt.event.InputEvent; + +public class InactiveFocusRace { + + static Frame activeFrame, inactiveFrame; + Button activeButton, inactiveButton1, inactiveButton2; + Semaphore sema; + final static int TIMEOUT = 10000; + + public static void main(String[] args) throws Exception { + try { + InactiveFocusRace test = new InactiveFocusRace(); + test.init(); + test.start(); + } finally { + if (activeFrame != null) { + activeFrame.dispose(); + } + if (inactiveFrame != null) { + inactiveFrame.dispose(); + } + } + } + + public void init() { + activeButton = new Button("active button"); + inactiveButton1 = new Button("inactive button1"); + inactiveButton2 = new Button("inactive button2"); + activeFrame = new Frame("Active frame"); + inactiveFrame = new Frame("Inactive frame"); + inactiveFrame.setLayout(new FlowLayout()); + activeFrame.add(activeButton); + inactiveFrame.add(inactiveButton1); + inactiveFrame.add(inactiveButton2); + activeFrame.pack(); + activeFrame.setLocation(300, 10); + inactiveFrame.pack(); + inactiveFrame.setLocation(300, 300); + sema = new Semaphore(); + + inactiveButton1.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + System.err.println("Button 1 got focus"); + } + }); + inactiveButton2.addFocusListener(new FocusAdapter() { + public void focusGained(FocusEvent e) { + System.err.println("Button2 got focus"); + sema.raise(); + } + }); + activeFrame.addWindowListener(new WindowAdapter() { + public void windowActivated(WindowEvent e) { + System.err.println("Window activated"); + sema.raise(); + } + }); + } + + public void start() { + Robot robot = null; + try { + robot = new Robot(); + } catch (Exception e) { + throw new RuntimeException("Unable to create robot"); + } + + inactiveFrame.setVisible(true); + activeFrame.setVisible(true); + + // Wait for active frame to become active + try { + sema.doWait(TIMEOUT); + } catch (InterruptedException ie) { + throw new RuntimeException("Wait was interrupted"); + } + if (!sema.getState()) { + throw new RuntimeException("Frame doesn't become active on show"); + } + sema.setState(false); + + // press on second button in inactive frame + Point loc = inactiveButton2.getLocationOnScreen(); + robot.mouseMove(loc.x+5, loc.y+5); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + + // after all second button should be focus owner. + try { + sema.doWait(TIMEOUT); + } catch (InterruptedException ie) { + throw new RuntimeException("Wait was interrupted"); + } + if (!sema.getState()) { + throw new RuntimeException("Button2 didn't become focus owner"); + } + Toolkit.getDefaultToolkit().sync(); + robot.waitForIdle(); + if (!(KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner() == inactiveButton2)) { + throw new RuntimeException("Button2 should be the focus owner after all"); + } + + } + +} + +class Semaphore { + boolean state = false; + int waiting = 0; + public Semaphore() { + } + public void doWait() throws InterruptedException { + synchronized(this) { + if (state) return; + waiting++; + wait(); + waiting--; + } + } + public void doWait(int timeout) throws InterruptedException { + synchronized(this) { + if (state) return; + waiting++; + wait(timeout); + waiting--; + } + } + public void raise() { + synchronized(this) { + state = true; + if (waiting > 0) { + notifyAll(); + } + } + } + public boolean getState() { + synchronized(this) { + return state; + } + } + public void setState(boolean newState) { + synchronized(this) { + state = newState; + } + } +} diff --git a/test/jdk/java/awt/Focus/InitialPrintDlgFocusTest.java b/test/jdk/java/awt/Focus/InitialPrintDlgFocusTest.java new file mode 100644 index 0000000000000..cc9d0c0371182 --- /dev/null +++ b/test/jdk/java/awt/Focus/InitialPrintDlgFocusTest.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2002, 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 + * @bug 4688591 + * @summary Tab key hangs in Native Print Dialog on win32 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual InitialPrintDlgFocusTest + */ + +import java.awt.BorderLayout; +import java.awt.Dialog; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.JobAttributes; +import java.awt.PageAttributes; +import java.awt.PrintJob; +import java.awt.Toolkit; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +import javax.swing.JButton; +import javax.swing.JFrame; + +public class InitialPrintDlgFocusTest { + + private static final String INSTRUCTIONS = """ + After the tests starts you will see a frame titled "PrintTest". + Press the "Print" button and the print dialog should appear. + If you are able to transfer focus between components of the Print dialog + using the TAB key, then the test passes else the test fails. + + Note: close the Print dialog before clicking on "Pass" or "Fail" buttons."""; + + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("InitialPrintDlgFocusTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(InitialPrintDlgFocusTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + return new PrintTest(); + + } +} + +class PrintTest extends JFrame implements ActionListener { + + JButton b; + JobAttributes jbattrib; + Toolkit tk ; + PageAttributes pgattrib; + + public PrintTest() { + setTitle("PrintTest"); + setSize(500, 400); + + b = new JButton("Print"); + jbattrib = new JobAttributes(); + tk = Toolkit.getDefaultToolkit(); + pgattrib = new PageAttributes(); + getContentPane().setLayout(new FlowLayout()); + getContentPane().add(b); + + b.addActionListener(this); + + } + + public void actionPerformed(ActionEvent ae) { + if(ae.getSource()==b) + jbattrib.setDialog(JobAttributes.DialogType.NATIVE); + + PrintJob pjob = tk.getPrintJob(this, "Printing Test", + jbattrib, pgattrib); + + } +} + diff --git a/test/jdk/java/awt/Focus/KeyStrokeTest.java b/test/jdk/java/awt/Focus/KeyStrokeTest.java new file mode 100644 index 0000000000000..7c462ce8f22d6 --- /dev/null +++ b/test/jdk/java/awt/Focus/KeyStrokeTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4845868 + * @summary REGRESSION: First keystroke after JDialog is closed is lost + * @key headful + * @run main KeyStrokeTest + */ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; + +public class KeyStrokeTest { + static boolean keyTyped; + static Frame frame; + + public static void main(String[] args) throws Exception { + try { + KeyStrokeTest test = new KeyStrokeTest(); + test.doTest(); + } finally { + if (frame != null) { + frame.dispose(); + } + } + } + + private static void doTest() throws Exception { + final Object monitor = new Object(); + frame = new Frame(); + TextField textField = new TextField() { + public void transferFocus() { + System.err.println("transferFocus()"); + final Dialog dialog = new Dialog(frame, true); + Button btn = new Button("Close It"); + btn.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.err.println("action performed"); + dialog.setVisible(false); + } + }); + dialog.add(btn); + dialog.setSize(200, 200); + dialog.setVisible(true); + } + }; + + textField.addKeyListener(new KeyAdapter() { + public void keyTyped(KeyEvent e) { + System.err.println(e); + if (e.getKeyChar() == 'a') { + keyTyped = true; + } + + synchronized (monitor) { + monitor.notifyAll(); + } + } + }); + frame.add(textField); + frame.setSize(400, 400); + frame.setVisible(true); + + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(1000); + robot.keyPress(KeyEvent.VK_TAB); + robot.keyRelease(KeyEvent.VK_TAB); + + robot.delay(1000); + robot.keyPress(KeyEvent.VK_SPACE); + robot.keyRelease(KeyEvent.VK_SPACE); + + robot.delay(1000); + synchronized (monitor) { + robot.keyPress(KeyEvent.VK_A); + robot.keyRelease(KeyEvent.VK_A); + monitor.wait(3000); + } + + if (!keyTyped) { + throw new RuntimeException("TEST FAILED"); + } + + System.out.println("Test passed"); + } + +} diff --git a/test/jdk/java/awt/Focus/LightweightPopupTest.java b/test/jdk/java/awt/Focus/LightweightPopupTest.java new file mode 100644 index 0000000000000..bc3dd0d038b9b --- /dev/null +++ b/test/jdk/java/awt/Focus/LightweightPopupTest.java @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2001, 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 + * @bug 4472032 + * @summary Switching between lightweight menus by horizontal arrow key works incorrect + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual LightweightPopupTest +*/ + +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JMenu; +import javax.swing.JMenuBar; +import javax.swing.JMenuItem; + +public class LightweightPopupTest { + + private static final String INSTRUCTIONS = """ + When the test starts, you will see a frame titled + 'Lightweight Popup Test', which contains a button + (titled 'JButton') and two menus ('Menu 1' and 'Menu 2'). + Make sure that both menus, when expanded, fit entirely + into the frame. Now take the following steps: + 1. Click on 'JButton' to focus it. + 2. Click 'Menu 1' to expand it. + 3. Press right arrow to select 'Menu 2'. + Now check where the focus is. If it is on 'JButton' + (you can press space bar to see if it is there), then + the test failed. If 'JButton' is not focused, then + the test passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("LightweightPopupTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(LightweightPopupTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + + JFrame frame = new JFrame("Lightweight Popup Test"); + JButton button = new JButton("JButton"); + JMenuBar menuBar = new JMenuBar(); + JMenu menu1 = new JMenu("Menu 1"); + menu1.add(new JMenuItem("Menu Item 1")); + menu1.add(new JMenuItem("Menu Item 2")); + menuBar.add(menu1); + JMenu menu2 = new JMenu("Menu 2"); + menu2.add(new JMenuItem("Menu Item 3")); + menu2.add(new JMenuItem("Menu Item 4")); + menuBar.add(menu2); + + frame.add(button); + frame.setJMenuBar(menuBar); + frame.setSize(300, 200); + return frame; + } + +} + diff --git a/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java b/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java new file mode 100644 index 0000000000000..a99ec4f0a0d90 --- /dev/null +++ b/test/jdk/java/awt/Focus/ProxiedWindowHideTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2001, 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 + * @bug 4396407 + * @summary Tests that after a proxied window is hidden, focus is being restored correctly + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ProxiedWindowHideTest +*/ + +import java.awt.BorderLayout; +import java.awt.Button; +import java.awt.Container; +import javax.swing.Box; +import javax.swing.JComboBox; +import javax.swing.JFrame; + +public class ProxiedWindowHideTest { + + private static final String INSTRUCTIONS = """ + You will see a JFrame. + Click on JComboBox, list will expand then select any item in it. + After selection, list should collapse. + Click on Button('Push'). + If you are able to make it focused by mouse click, + (black rectangle will appear around it) the test is PASSED, + otherwise the test is FAILED."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ProxiedWindowHideTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ProxiedWindowHideTest::createTestUI) + .build() + .awaitAndCheck(); + } + + private static JFrame createTestUI() { + JFrame frame = new JFrame("ProxiedWindowHideTest frame"); + String[] petStrings = { "Bird", "Cat", "Dog", "Rabbit", "Pig" }; + JComboBox cb = new JComboBox(petStrings); + + cb.setLightWeightPopupEnabled(false); + Container parent = Box.createVerticalBox(); + parent.add(new Button("Push")); + parent.add(cb); + frame.add(parent, BorderLayout.CENTER); + frame.pack(); + return frame; + } + +} + diff --git a/test/jdk/java/awt/Focus/RequestInInactiveFrame.java b/test/jdk/java/awt/Focus/RequestInInactiveFrame.java new file mode 100644 index 0000000000000..3297fe17501a1 --- /dev/null +++ b/test/jdk/java/awt/Focus/RequestInInactiveFrame.java @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2011, 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 + * @bug 6458497 + * @summary check focus requests in inactive frames + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RequestInInactiveFrame + */ + +import java.util.ArrayList; + +import java.awt.FlowLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.Window; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.SwingUtilities; + +public class RequestInInactiveFrame { + + private static final String INSTRUCTIONS = """ + After the tests starts you will see two frames: \"test frame\" and \"opposite frame\" + activate the former by click on its title + Focus should be on \"press me\" button (if it's not, the test fails) + press on \"press me\" button and activate \"opposite frame\" + wait for several seconds. + Focus should either remain on button in the \"opposite frame\" + or goes to \"focus target\" button (in this case \"test frame\" should be activated + if it's not, the test failed. + Activate \"test frame\" one more time, press on \"press me\" button and switch focus + to some native window. Wait for several seconds, + If you see focus border around + \"focus target\" and \"test frame\" is not active then the test failed. + if focus transfered to that button and the frame is activated, or if there is no focus + in java - tests passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("RequestInInactiveFrame Instructions") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(RequestInInactiveFrame::createTestUI) + .build() + .awaitAndCheck(); + } + + private static ArrayList createTestUI() { + JFrame frame = new JFrame("test frame"); + final JButton btn2 = new JButton("focus target"); + JButton btn1 = new JButton("press me"); + btn1.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent e) { + System.out.println("waiting..."); + try { + Thread.sleep(3000); + } catch (InterruptedException ie) { + ie.printStackTrace(); + } + System.out.println("requesting focus"); + btn2.requestFocus(); + } + }); + frame.setLayout(new FlowLayout()); + frame.add(btn1); + frame.add(btn2); + frame.pack(); + frame.setLocation(200, 100); + + JFrame frame2 = new JFrame("opposite frame"); + JButton btn3 = new JButton("just a button"); + frame2.add(btn3); + frame2.pack(); + frame2.setLocation(200, 200); + + ArrayList list = new ArrayList<>(); + list.add(frame); + list.add(frame2); + return list; + } + +} diff --git a/test/jdk/java/awt/Frame/DefaultLocationTest.java b/test/jdk/java/awt/Frame/DefaultLocationTest.java new file mode 100644 index 0000000000000..dfeb5e93e3c89 --- /dev/null +++ b/test/jdk/java/awt/Frame/DefaultLocationTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1998, 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.EventQueue; +import java.awt.Frame; +import java.awt.Label; + +/* + * @test + * @bug 4085599 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Test default location for frame + * @run main/manual DefaultLocationTest + */ + +public class DefaultLocationTest { + private static Frame f; + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + A small frame containing the label 'Hello World' should + appear in the upper left hand corner of the screen. The + exact location is dependent upon the window manager. + + On Linux and Mac machines, the default location for frame + is below the taskbar or close to top-left corner. + + Upon test completion, click Pass or Fail appropriately."""; + + PassFailJFrame passFailJFrame = new PassFailJFrame("DefaultLocationTest " + + " Instructions", INSTRUCTIONS, 5, 10, 40); + EventQueue.invokeAndWait(DefaultLocationTest::createAndShowUI); + passFailJFrame.awaitAndCheck(); + } + + private static void createAndShowUI() { + f = new Frame("DefaultLocation"); + f.add("Center", new Label("Hello World")); + f.pack(); + PassFailJFrame.addTestWindow(f); + PassFailJFrame.positionTestWindow( + null, PassFailJFrame.Position.HORIZONTAL); + f.setVisible(true); + } +} diff --git a/test/jdk/java/awt/Frame/EmptyFrameTest.java b/test/jdk/java/awt/Frame/EmptyFrameTest.java new file mode 100644 index 0000000000000..7a324a3cbc994 --- /dev/null +++ b/test/jdk/java/awt/Frame/EmptyFrameTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999, 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.Color; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.IOException; +import javax.imageio.ImageIO; + +/* + * @test + * @bug 4237529 + * @key headful + * @summary Test repainting of an empty frame + * @run main EmptyFrameTest + */ + +public class EmptyFrameTest { + private static Frame f; + private static Robot robot; + private static volatile Point p; + private static volatile Dimension d; + private static final int TOLERANCE = 5; + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + try { + EventQueue.invokeAndWait(() -> { + createAndShowUI(); + }); + robot.delay(1000); + f.setSize(50, 50); + robot.delay(500); + EventQueue.invokeAndWait(() -> { + p = f.getLocation(); + d = f.getSize(); + }); + Rectangle rect = new Rectangle(p, d); + BufferedImage img = robot.createScreenCapture(rect); + if (chkImgBackgroundColor(img)) { + try { + ImageIO.write(img, "png", new File("Frame.png")); + } catch (IOException ignored) {} + throw new RuntimeException("Frame doesn't repaint itself on resize"); + } + } finally { + EventQueue.invokeAndWait(() -> { + if (f != null) { + f.dispose(); + } + }); + } + } + + private static void createAndShowUI() { + f = new Frame("EmptyFrameTest"); + f.setUndecorated(true); + f.setBackground(Color.RED); + f.setVisible(true); + } + + private static boolean chkImgBackgroundColor(BufferedImage img) { + for (int x = 1; x < img.getWidth() - 1; ++x) { + for (int y = 1; y < img.getHeight() - 1; ++y) { + Color c = new Color(img.getRGB(x, y)); + if ((c.getRed() - Color.RED.getRed()) > TOLERANCE) { + return true; + } + } + } + return false; + } +} diff --git a/test/jdk/java/awt/Frame/FrameLayoutTest.java b/test/jdk/java/awt/Frame/FrameLayoutTest.java new file mode 100644 index 0000000000000..d6e994beaace0 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameLayoutTest.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1999, 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.BorderLayout; +import java.awt.Button; +import java.awt.Frame; + +/* + * @test + * @bug 4173503 + * @library /java/awt/regtesthelpers + * @requires (os.family == "windows") + * @build PassFailJFrame + * @summary Tests that frame layout is performed when frame is maximized from taskbar + * @run main/manual FrameLayoutTest + */ + +public class FrameLayoutTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Right-click on the taskbar button for this test. In the menu appeared, + choose Maximize. The frame will be maximized. Check if buttons inside + the frame are laid out properly, i.e. they occupy the frame entirely. + + If so, test passes. If buttons occupy small rectangle in the top left + corner, test fails."""; + + PassFailJFrame.builder() + .title("Frame's Layout Test Instruction") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(FrameLayoutTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("Maximize Test"); + f.add(new Button("North"), BorderLayout.NORTH); + f.add(new Button("South"), BorderLayout.SOUTH); + f.add(new Button("East"), BorderLayout.EAST); + f.add(new Button("West"), BorderLayout.WEST); + f.add(new Button("Cent"), BorderLayout.CENTER); + f.pack(); + f.setState(Frame.ICONIFIED); + return f; + } +} diff --git a/test/jdk/java/awt/Frame/FrameSetMinimumSizeTest.java b/test/jdk/java/awt/Frame/FrameSetMinimumSizeTest.java new file mode 100644 index 0000000000000..929a36e773e40 --- /dev/null +++ b/test/jdk/java/awt/Frame/FrameSetMinimumSizeTest.java @@ -0,0 +1,91 @@ +/* + * 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.Dimension; +import java.awt.EventQueue; +import java.awt.Frame; + +/* + * @test + * @bug 4320050 + * @key headful + * @summary Minimum size for java.awt.Frame is not being enforced. + * @run main FrameSetMinimumSizeTest + */ + +public class FrameSetMinimumSizeTest { + private static Frame f; + private static volatile boolean passed; + + public static void main(String[] args) throws Exception { + EventQueue.invokeAndWait(() -> { + try { + createAndShowUI(); + + f.setSize(200, 200); + passed = verifyFrameSize(new Dimension(300, 300)); + isFrameSizeOk(passed); + + f.setSize(200, 400); + passed = verifyFrameSize(new Dimension(300, 400)); + isFrameSizeOk(passed); + + f.setSize(400, 200); + passed = verifyFrameSize(new Dimension(400, 300)); + isFrameSizeOk(passed); + + f.setMinimumSize(null); + + f.setSize(200, 200); + passed = verifyFrameSize(new Dimension(200, 200)); + isFrameSizeOk(passed); + } finally { + if (f != null) { + f.dispose(); + } + } + }); + } + + private static void createAndShowUI() { + f = new Frame("Minimum Size Test"); + f.setSize(300, 300); + f.setMinimumSize(new Dimension(300, 300)); + f.setVisible(true); + } + + private static boolean verifyFrameSize(Dimension expected) { + + if (f.getSize().width != expected.width || f.getSize().height != expected.height) { + return false; + } + return true; + } + + private static void isFrameSizeOk(boolean passed) { + if (!passed) { + throw new RuntimeException("Frame's setMinimumSize not honoured for the" + + " frame size: " + f.getSize()); + } + } +} diff --git a/test/jdk/java/awt/Frame/PackTwiceTest.java b/test/jdk/java/awt/Frame/PackTwiceTest.java new file mode 100644 index 0000000000000..63cd20612f0d3 --- /dev/null +++ b/test/jdk/java/awt/Frame/PackTwiceTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2001, 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.Frame; +import java.awt.TextField; + +/* + * @test + * @bug 4097744 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary packing a frame twice stops it resizing + * @run main/manual PackTwiceTest + */ + +public class PackTwiceTest { + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + 1. You would see a Frame titled 'TestFrame' + 2. The Frame displays a text as below: + 'I am a lengthy sentence...can you see me?' + 3. If you can see the full text without resizing the frame + using mouse, press 'Pass' else press 'Fail'."""; + + PassFailJFrame.builder() + .title("PackTwiceTest Instruction") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(PackTwiceTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame f = new Frame("PackTwiceTest TestFrame"); + TextField tf = new TextField(); + f.add(tf, "Center"); + tf.setText("I am a short sentence"); + f.pack(); + f.pack(); + tf.setText("I am a lengthy sentence...can you see me?"); + f.pack(); + f.requestFocus(); + return f; + } +} diff --git a/test/jdk/java/awt/MenuItem/GiantFontTest.java b/test/jdk/java/awt/MenuItem/GiantFontTest.java new file mode 100644 index 0000000000000..f1e352373bb1e --- /dev/null +++ b/test/jdk/java/awt/MenuItem/GiantFontTest.java @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2002, 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.Font; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +/* + * @test + * @bug 4700350 + * @requires os.family != "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests menu item font is big + * @run main/manual GiantFontTest + */ + +public class GiantFontTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + A frame with one menu will appear. + On Linux, the menu's (present on menu bar) font should + be quite large (48 point). + If not, test fails. + + On Windows, the menu's (present on menu bar) font + should be normal size. + If the menu text is clipped by the title bar, or is painted over + the title bar or client area, the test fails. + + On both Windows and Linux, the menu items in the popup + menu should be large. + + If so, test passes."""; + + PassFailJFrame.builder() + .title("GiantFontTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(GiantFontTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Font giantFont = new Font("Dialog", Font.PLAIN, 48); + Frame f = new Frame("GiantFontTest"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("My font is too big!"); + m.setFont(giantFont); + for (int i = 0; i < 5; i++) { + m.add(new MenuItem("Some MenuItems")); + } + mb.add(m); + f.setMenuBar(mb); + f.setSize(450, 400); + return f; + } +} diff --git a/test/jdk/java/awt/MenuItem/LotsOfMenuItemsTest.java b/test/jdk/java/awt/MenuItem/LotsOfMenuItemsTest.java new file mode 100644 index 0000000000000..7a528205d27d8 --- /dev/null +++ b/test/jdk/java/awt/MenuItem/LotsOfMenuItemsTest.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 1998, 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.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ComponentAdapter; +import java.awt.event.ComponentEvent; + +/* + * @test + * @bug 4175790 + * @requires os.family == "windows" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Win32: Running out of command ids for menu items + * @run main/manual LotsOfMenuItemsTest + */ + +public class LotsOfMenuItemsTest extends ComponentAdapter { + private static final int NUM_WINDOWS = 400; + private static TestFrame firstFrame; + + public static void main(String[] args) throws Exception { + LotsOfMenuItemsTest obj = new LotsOfMenuItemsTest(); + String INSTRUCTIONS = """ + This test creates lots of frames with menu bars. + When it's done you will see two frames. + Try to select menu items from each of them. + + If everything seems to work - test passed. + Click "Pass" button in the test harness window. + + If test crashes on you - test failed."""; + + PassFailJFrame.builder() + .title("LotsOfMenuItemsTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(obj::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private Frame createAndShowUI() { + firstFrame = new TestFrame("First frame"); + firstFrame.addComponentListener(this); + return firstFrame; + } + + @Override + public void componentShown(ComponentEvent e) { + final int x = firstFrame.getX(); + final int y = firstFrame.getY() + firstFrame.getHeight() + 8; + TestFrame testFrame; + for (int i = 1; i < NUM_WINDOWS - 1; ++i) { + testFrame = new TestFrame("Running(" + i + ")...", x, y); + testFrame.setVisible(false); + testFrame.dispose(); + } + testFrame = new TestFrame("Last Frame", x, y); + PassFailJFrame.addTestWindow(testFrame); + } + + private static class TestFrame extends Frame { + static int n = 0; + + public TestFrame(String title) { + this(title, 0, 0, false); + } + + public TestFrame(String s, int x, int y) { + this(s, x, y, true); + } + + private TestFrame(String title, int x, int y, boolean visible) { + super(title); + MenuBar mb = new MenuBar(); + for (int i = 0; i < 10; ++i) { + Menu m = new Menu("Menu_" + (i + 1)); + for (int j = 0; j < 20; ++j) { + MenuItem mi = new MenuItem("Menu item " + ++n); + m.add(mi); + } + mb.add(m); + } + setMenuBar(mb); + setLocation(x, y); + setSize(450, 150); + if (visible) { + setVisible(true); + } + } + } +} diff --git a/test/jdk/java/awt/MenuItem/MenuSetFontTest.java b/test/jdk/java/awt/MenuItem/MenuSetFontTest.java new file mode 100644 index 0000000000000..9a4e8f8583905 --- /dev/null +++ b/test/jdk/java/awt/MenuItem/MenuSetFontTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2000, 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.Font; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +/* + * @test + * @bug 4066657 8009454 + * @requires os.family != "mac" + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Tests that setting a font on the Menu with MenuItem takes effect. + * @run main/manual MenuSetFontTest + */ + +public class MenuSetFontTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Look at the menu in the upper left corner of the 'SetFont Test' frame. + Click on the "File" menu. You will see "menu item" item. + Press Pass if menu item is displayed using bold and large font, + otherwise press Fail. + If you do not see menu at all, press Fail."""; + + PassFailJFrame.builder() + .title("MenuSetFontTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(MenuSetFontTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("SetFont Test"); + MenuBar menuBar = new MenuBar(); + Menu menu = new Menu("File"); + MenuItem item = new MenuItem("menu item"); + menu.add(item); + menuBar.add(menu); + menuBar.setFont(new Font(Font.MONOSPACED, Font.BOLD, 24)); + frame.setMenuBar(menuBar); + frame.setSize(300, 200); + return frame; + } +} diff --git a/test/jdk/java/awt/MenuItem/NullOrEmptyStringLabelTest.java b/test/jdk/java/awt/MenuItem/NullOrEmptyStringLabelTest.java new file mode 100644 index 0000000000000..79d4c02ad246a --- /dev/null +++ b/test/jdk/java/awt/MenuItem/NullOrEmptyStringLabelTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1999, 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.BorderLayout; +import java.awt.Button; +import java.awt.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +/* + * @test + * @bug 4251036 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary MenuItem setLabel(null/"") behaves differently under Win32 and Solaris + * @run main/manual NullOrEmptyStringLabelTest + */ + +public class NullOrEmptyStringLabelTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + The bug is reproducible under Win32 and Solaris. + Setting 'null' and "" as a label of menu item + should set blank label on all platforms according to the specification. + But under Solaris setting "" as a label of menu item used to + cause some garbage to be set as label. + Under Win32 setting 'null' as a label used to result in + throwing NullPointerException. + + If you see any of these things happen test fails otherwise + it passes."""; + + PassFailJFrame.builder() + .title("NullOrEmptyStringLabelTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(NullOrEmptyStringLabelTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + + private static Frame createAndShowUI() { + Frame frame = new Frame("Null Or Empty String Label Test"); + Menu menu = new Menu("Menu"); + MenuItem mi = new MenuItem("Item"); + MenuBar mb = new MenuBar(); + Button button1 = new Button("Set MenuItem label to 'null'"); + Button button2 = new Button("Set MenuItem label to \"\""); + Button button3 = new Button("Set MenuItem label to 'text'"); + button1.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + System.out.println("Setting MenuItem label to null"); + mi.setLabel(null); + } + }); + button2.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + System.out.println("Setting MenuItem label to \"\""); + mi.setLabel(""); + } + }); + button3.addActionListener(new ActionListener() { + @Override + public void actionPerformed(ActionEvent ev) { + System.out.println("Setting MenuItem label to 'text'"); + mi.setLabel("text"); + } + }); + menu.add(mi); + mb.add(menu); + frame.add(button1, BorderLayout.NORTH); + frame.add(button2, BorderLayout.CENTER); + frame.add(button3, BorderLayout.SOUTH); + frame.setMenuBar(mb); + frame.setSize(200, 135); + return frame; + } +} diff --git a/test/jdk/java/awt/MenuItem/UnicodeMenuItemTest.java b/test/jdk/java/awt/MenuItem/UnicodeMenuItemTest.java new file mode 100644 index 0000000000000..b73fe954af6db --- /dev/null +++ b/test/jdk/java/awt/MenuItem/UnicodeMenuItemTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 1999, 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.Frame; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; + +/* + * @test + * @bug 4099695 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary menu items with Unicode labels treated as separators + * @run main/manual UnicodeMenuItemTest + */ + +public class UnicodeMenuItemTest { + + public static void main(String[] args) throws Exception { + String INSTRUCTIONS = """ + Click on the "Menu" on the top-left corner of frame. + + The menu should have four entries: + 1) a row of five unicode characters: \u00c4\u00cb\u00cf\u00d6\u00dc + 2) a menu separator + 3) a unicode character: \u012d + 4) a unicode character: \u022d + + If the menu items look like the list above, the test passes. + It is okay if the unicode characters look like empty boxes + or something - as long as they are not separators. + + If either of the last two menu items show up as separators, + the test FAILS. + + Press 'Pass' if above instructions hold good else press 'Fail'."""; + + PassFailJFrame.builder() + .title("UnicodeMenuItemTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(40) + .testUI(UnicodeMenuItemTest::createAndShowUI) + .build() + .awaitAndCheck(); + } + private static Frame createAndShowUI() { + Frame frame = new Frame("Unicode MenuItem Test"); + MenuBar mb = new MenuBar(); + Menu m = new Menu("Menu"); + + MenuItem mi1 = new MenuItem("\u00c4\u00cb\u00cf\u00d6\u00dc"); + m.add(mi1); + + MenuItem separator = new MenuItem("-"); + m.add(separator); + + MenuItem mi2 = new MenuItem("\u012d"); + m.add(mi2); + + MenuItem mi3 = new MenuItem("\u022d"); + m.add(mi3); + + mb.add(m); + + frame.setMenuBar(mb); + frame.setSize(450, 150); + return frame; + } +} diff --git a/test/jdk/java/awt/Robot/CreateScreenCapture.java b/test/jdk/java/awt/Robot/CreateScreenCapture.java new file mode 100644 index 0000000000000..8060240ba8f1d --- /dev/null +++ b/test/jdk/java/awt/Robot/CreateScreenCapture.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4292503 + * @summary OutOfMemoryError with lots of Robot.createScreenCapture + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @requires (os.family == "linux") + * @run main/manual CreateScreenCapture +*/ + +import java.awt.Dialog; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.TextArea; + +public class CreateScreenCapture { + + static TextArea messageText; + + private static final String INSTRUCTIONS = """ + This test is linux only! + Once you see these instructions, run 'top' program. + Watch for java process. + The memory size used by this process should stop growing after several steps. + Numbers of steps test is performing are displayed in output window. + After 5-7 steps the size taken by the process should become stable. + If this happens, then test passed otherwise test failed. + + Small oscillations of the memory size are, however, acceptable."""; + + public static void main(String[] args) throws Exception { + Robot robot = new Robot(); + PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS); + Dialog dialog = new Dialog(new Frame(), "Instructions"); + messageText = new TextArea("", 5, 80, TextArea.SCROLLBARS_BOTH); + dialog.add(messageText); + PassFailJFrame.addTestWindow(dialog); + PassFailJFrame.positionTestWindow(dialog, PassFailJFrame.Position.HORIZONTAL); + dialog.setSize(200, 300); + dialog.setVisible(true); + Rectangle rect = new Rectangle(0, 0, 1000, 1000); + for (int i = 0; i < 100; i++) { + Image image = robot.createScreenCapture(rect); + image.flush(); + image = null; + robot.delay(200); + log("step #" + i); + } + passFail.awaitAndCheck(); + } + + private static void log(String messageIn) { + messageText.append(messageIn + "\n"); + } +} + diff --git a/test/jdk/java/awt/Robot/RobotScrollTest.java b/test/jdk/java/awt/Robot/RobotScrollTest.java new file mode 100644 index 0000000000000..20dc9f2f4ebd9 --- /dev/null +++ b/test/jdk/java/awt/Robot/RobotScrollTest.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2001, 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 + * @bug 4374578 + * @summary Test robot wheel scrolling of Text + * @requires (os.family == "Windows") | (os.family == "linux") + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual RobotScrollTest +*/ + +import java.awt.Frame; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Robot; +import java.awt.TextArea; + +public class RobotScrollTest { + + static TextArea ta; + static Robot robot; + + private static final String INSTRUCTIONS = """ + 0. DON'T TOUCH ANYTHING! + 1. This test is for Windows and Linux only. + 2. Just sit back, and watch the Robot move the mouse to the TextArea. + 3. Once the pointer is on the text area, the Robot will use the mouse wheel + to scroll the text. + If the text scrolled, press PASS, else, press FAIL."""; + + public static void main(String[] args) throws Exception { + robot = new Robot(); + robot.setAutoDelay(100); + PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS); + createTestUI(); + passFail.awaitAndCheck(); + } + + private static void createTestUI() { + Frame f = new Frame("RobotScrollTest"); + ta = new TextArea(); + for (int i = 0; i < 100; i++) { + ta.append(i + "\n"); + } + f.add(ta); + f.setLocation(0, 400); + f.pack(); + PassFailJFrame.addTestWindow(f); + PassFailJFrame.positionTestWindow(f, PassFailJFrame.Position.HORIZONTAL); + f.setVisible(true); + doTest(); + } + + private static void doTest() { + robot.waitForIdle(); + robot.delay(1000); + // get loc of TextArea + Point taAt = ta.getLocationOnScreen(); + // get bounds of button + Rectangle bounds = ta.getBounds(); + + // move mouse to middle of button + robot.mouseMove(taAt.x + bounds.width / 2, + taAt.y + bounds.height / 2); + + // rotate wheel a few times + for (int j = 1; j < 8; j++) { + for (int k = 0; k < 5; k++) { + robot.mouseWheel(j); + } + + for (int k = 0; k < 5; k++) { + robot.mouseWheel(-1 * j); + } + } + } + +} + diff --git a/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java new file mode 100644 index 0000000000000..56a39758874e6 --- /dev/null +++ b/test/jdk/java/awt/TextField/CaretPositionTest/CaretPositionTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1997, 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.AWTException; +import java.awt.Button; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.InputEvent; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4038580 + * @key headful + * @requires os.family != "windows" + * @summary Caret position not accurate in presence of selected areas + * @run main CaretPositionTest + */ + +public class CaretPositionTest extends Frame { + private TextField text_field; + private Button caretpos_button; + private Point onScreen; + private Dimension size; + String text = "12 45 789"; + private static volatile int position = -1; + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + CaretPositionTest test = new CaretPositionTest(); + EventQueue.invokeAndWait(test::setupGUI); + try { + test.test(); + if (position != 9) { + throw new RuntimeException("Caret position should be at the end of the string"); + } + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } + + public void setupGUI() { + setLocationRelativeTo(null); + setTitle("CaretPositionTest"); + setLayout(new FlowLayout()); + text_field = new TextField(text, 9); + caretpos_button=new Button("CaretPosition"); + add(text_field); + add(caretpos_button); + pack(); + setVisible(true); + toFront(); + } + + public void test() throws AWTException, InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + onScreen = text_field.getLocationOnScreen(); + size = text_field.getSize(); + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + int y = onScreen.y + (size.height / 2); + robot.mouseMove(onScreen.x + (size.width / 2), y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseMove(onScreen.x + 3, y); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + for (int x = onScreen.x + 5; x < onScreen.x + size.width; x += 2) { + robot.mouseMove(x, y); + } + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.waitForIdle(); + EventQueue.invokeAndWait(() -> { + position = text_field.getCaretPosition(); + }); + } +} diff --git a/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java new file mode 100644 index 0000000000000..ab5aebc11d47a --- /dev/null +++ b/test/jdk/java/awt/TextField/GetTextTest/GetTextTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1998, 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 + * @bug 4100188 + * @key headful + * @summary Make sure that TextFields contain all of, + * and exactly, the text that was entered into them. + * @run main GetTextTest + */ + +import java.awt.AWTException; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.Point; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; +import java.lang.reflect.InvocationTargetException; + +public class GetTextTest extends Frame implements ActionListener { + private final String s = "test string"; + private volatile String ac; + private TextField t; + private Point location; + private Dimension size; + + public void setupGUI() { + setLayout(new FlowLayout(FlowLayout.LEFT)); + + t = new TextField(s, 32); + add(new Label("Hit after text")); + add(t); + t.addActionListener(this); + setLocationRelativeTo(null); + pack(); + setVisible(true); + } + + public void actionPerformed(ActionEvent evt) { + ac = evt.getActionCommand(); + } + + public void performTest() throws AWTException, InterruptedException, + InvocationTargetException { + EventQueue.invokeAndWait(() -> { + location = t.getLocationOnScreen(); + size = t.getSize(); + }); + Robot robot = new Robot(); + robot.setAutoDelay(50); + robot.delay(1000); + robot.waitForIdle(); + robot.mouseMove(location.x + size.width - 3, location.y + (size.height / 2)); + robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); + robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); + robot.delay(1000); + robot.waitForIdle(); + robot.keyPress(KeyEvent.VK_ENTER); + robot.keyRelease(KeyEvent.VK_ENTER); + robot.delay(1000); + if (!s.equals(ac)) { + throw new RuntimeException("Action command should be the same as text field content"); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException, AWTException { + GetTextTest test = new GetTextTest(); + EventQueue.invokeAndWait(test::setupGUI); + try { + test.performTest(); + } finally { + EventQueue.invokeAndWait(test::dispose); + } + } +} diff --git a/test/jdk/java/awt/TextField/SetBoundsTest/SetBoundsTest.java b/test/jdk/java/awt/TextField/SetBoundsTest/SetBoundsTest.java new file mode 100644 index 0000000000000..e37f69232ebec --- /dev/null +++ b/test/jdk/java/awt/TextField/SetBoundsTest/SetBoundsTest.java @@ -0,0 +1,123 @@ +/* + * 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.Color; +import java.awt.Container; +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.GridLayout; +import java.awt.Panel; +import java.awt.ScrollPane; +import java.awt.TextArea; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 6198290 6277332 + * @summary TextField painting is broken when placed on a Scrollpane, XToolkit + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetBoundsTest + */ + +public class SetBoundsTest extends Frame { + + private static final String INSTRUCTIONS = """ + 1) Make active a frame with a scrollpane and a few components. + 2) Please, focus attention on the text components + placed on the upper half of the frame + 3) Make sure, that the scrollbar of the frame + have the same position during the test. + 4) Bring focus to TextField, try deleting the text. + If the text never gets erased, the test failed + 5) Bring focus to TextArea, try deleting the text. + If the text never gets erased, the test failed + 6) Please, focus attention on the text components + placed on the lower half of the frame + 7) Try input something into TextField. + If you can not input anything into TextField, the test failed + 8) Try input something into TextArea. + If you can not input anything into TextArea, the test failed + 9) The test passed + """; + + public SetBoundsTest() { + setTitle("SetBoundsTest Test Frame"); + setLayout(new GridLayout(2, 1)); + Panel hw = new Panel(); + ScrollPane sp = new ScrollPane(ScrollPane.SCROLLBARS_AS_NEEDED); + Container lw = new Container(); + fill(hw); + fill(lw); + + sp.add(hw); + add(sp); + add(lw); + + setSize(600, 600); + sp.setScrollPosition(20, 0); + + } + + private void fill(Container c) { + Button button = new Button("button"); + c.add(button); + button.setBackground(new Color(0xd3ceac)); + button.setForeground(new Color(0x000000)); + button.move(60, 80); + button.resize(400, 60); + button.show(true); + + TextField textfield = new TextField("textfield"); + c.add(textfield); + textfield.setBackground(new Color(0xd3ceac)); + textfield.setForeground(new Color(0x000000)); + textfield.move(60, 20); + textfield.resize(400, 40); + textfield.show(true); + + TextArea textarea = new TextArea("textarea"); + c.add(textarea); + textarea.setBackground(new Color(0xd3ceac)); + textarea.setForeground(new Color(0x000000)); + textarea.move(60, 80); + textarea.resize(400, 60); + textarea.show(true); + + c.setLayout (new FlowLayout()); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Bounds Test Instructions") + .instructions(INSTRUCTIONS) + .testUI(SetBoundsTest::new) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java new file mode 100644 index 0000000000000..10779365defc4 --- /dev/null +++ b/test/jdk/java/awt/TextField/SetEchoCharTest3/SetEchoCharTest3.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4222122 + * @summary TextField.setEchoCharacter() seems to be broken + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetEchoCharTest3 + */ + +import java.awt.FlowLayout; +import java.awt.Frame; +import java.awt.Label; +import java.awt.TextField; +import java.lang.reflect.InvocationTargetException; + +public class SetEchoCharTest3 extends Frame { + static String INSTRUCTIONS = """ + Type in the text field and "*" characters should echo. + If only one "*" echoes and then the system beeps after + the second character is typed, then press Fail, otherwise press Pass. + """; + public SetEchoCharTest3() { + setLayout(new FlowLayout()); + add(new Label("Enter text:")); + TextField tf = new TextField(15); + tf.setEchoChar('*'); + add(tf); + pack(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Echo Char Test 3") + .testUI(SetEchoCharTest3::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/SetEchoCharTest4/SetEchoCharTest4.java b/test/jdk/java/awt/TextField/SetEchoCharTest4/SetEchoCharTest4.java new file mode 100644 index 0000000000000..c1cc07afac0ad --- /dev/null +++ b/test/jdk/java/awt/TextField/SetEchoCharTest4/SetEchoCharTest4.java @@ -0,0 +1,101 @@ +/* + * Copyright (c) 1999, 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.FlowLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4226580 + * @summary TextField with echoChar add+remove+add seems to be broken + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetEchoCharTest4 + */ + +public class SetEchoCharTest4 extends Frame implements ActionListener { + TextField tf1 = new TextField(8); + TextField tf2 = new TextField(8); + TextField tf3 = new TextField(8); + Button b = new Button("Click Several Times"); + + static final String INSTRUCTIONS = """ + Type in the first text field and * characters will echo. + Type in the second text field and $ characters will echo. + Type in the third text field and # characters will echo. + + Hit the button several times. All characters should remain + the same and the test should not crash. + + Make sure the actual text matches what you typed in for each field. + Press Pass if everything's ok, otherwise Fail + """; + + public SetEchoCharTest4() { + setLayout(new FlowLayout()); + tf1.setEchoChar('*'); + tf2.setEchoChar('$'); + tf3.setEchoChar('#'); + addStuff(); + b.addActionListener(this); + setSize (200,200); + } + + private void addStuff() { + add(tf1); + add(tf2); + add(tf3); + add(b); + } + + public void actionPerformed(ActionEvent ae) { + PassFailJFrame.log("TextField1 = " + tf1.getText()); + PassFailJFrame.log("TextField2 = " + tf2.getText()); + PassFailJFrame.log("TextField3 = " + tf3.getText()); + PassFailJFrame.log("--------------"); + setVisible(false); + remove(tf1); + remove(tf2); + remove(tf3); + remove(b); + addStuff(); + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Echo Character Test") + .testUI(SetEchoCharTest4::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/SetPasswordTest/SetPasswordTest.java b/test/jdk/java/awt/TextField/SetPasswordTest/SetPasswordTest.java new file mode 100644 index 0000000000000..cff5e3750173e --- /dev/null +++ b/test/jdk/java/awt/TextField/SetPasswordTest/SetPasswordTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 1997, 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.FlowLayout; +import java.awt.Frame; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4084454 + * @summary Make sure that you can set the text in a "password mode" + * text field and that it echoes as the current echo char. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual SetPasswordTest + */ + +public class SetPasswordTest extends Frame implements ActionListener { + private String setText = "Set text"; + private String getText = "Get text"; + private TextField tfPassword; + + static final String INSTRUCTIONS = """ + The purpose of this test is to ensure that when using a textField for + password entry that text set programmatically is not shown in the clear. + + We also test "pasting" text into the text field. + + 1. Press the "Set Text" button + Text should appear as '*' chars + - if the string "secret" appears then the test is failed. + 2. Use the mouse to select (highlight) all the text and press the DELETE key + 3. Use the system's copy/paste functionality to copy a text string from the + desktop or this window, and paste it into the text field. + 4. Text should appear in the text field as '*' chars + - if the string you pasted appears then the test is failed. + 5. press the "Get Text" button and the string you pasted + should be printed in the log area + - if it prints echo symbols instead the test is failed. + """; + + public SetPasswordTest() { + setLayout(new FlowLayout()); + tfPassword = new TextField("Initial text", 30); + tfPassword.setEchoChar('*'); + add(tfPassword); + + Button b1 = new Button(setText); + b1.addActionListener(this); + add(b1); + + Button b2 = new Button(getText); + b2.addActionListener(this); + add(b2); + pack(); + } + + public void actionPerformed(ActionEvent evt) { + String ac = evt.getActionCommand(); + if (setText.equals(ac)) { + tfPassword.setText("secret"); + } + + if (getText.equals(ac)) { + PassFailJFrame.log("Text: \"" + tfPassword.getText() + "\""); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Set Password Test") + .testUI(SetPasswordTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .logArea() + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/TextField/ZeroEchoCharTest/ZeroEchoCharTest.java b/test/jdk/java/awt/TextField/ZeroEchoCharTest/ZeroEchoCharTest.java new file mode 100644 index 0000000000000..274cec225729c --- /dev/null +++ b/test/jdk/java/awt/TextField/ZeroEchoCharTest/ZeroEchoCharTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2000, 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.Frame; +import java.awt.GridLayout; +import java.awt.TextField; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.lang.reflect.InvocationTargetException; + +/* + * @test + * @bug 4307281 + * @summary verify that after setting the echo char to 0 disguises are + * removed and user input is echoed to the screen unchanged. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ZeroEchoCharTest + */ + +public class ZeroEchoCharTest extends Frame implements ActionListener { + private final TextField textfield = new TextField(); + private final Button button1 = new Button("Set echo char to *"); + private final Button button2 = new Button("Set echo char to 0"); + static final String INSTRUCTIONS = """ + 1.Type in the text field. The user input must be echoed unchanged. + 2.Set echo char to '*' by pressing the corresponding button. + If all characters in the text field aren't immediately replaced + with '*', the test fails. + 3.Set echo char to 0 by pressing the corresponding button. + If disguises in the text field don't immediately revert to + the original characters, the test fails. + 4.Type in the text field. If the input is echoed unchanged, + the test passes. Otherwise, the test fails. + """; + + public ZeroEchoCharTest() { + button1.addActionListener(this); + button2.addActionListener(this); + + setLayout(new GridLayout(3, 1)); + + add(textfield); + add(button1); + add(button2); + pack(); + } + + public void actionPerformed(ActionEvent event) { + if (event.getSource() == button1) { + textfield.setEchoChar('*'); + } else if (event.getSource() == button2) { + textfield.setEchoChar((char)0); + } + } + + public static void main(String[] args) throws InterruptedException, + InvocationTargetException { + PassFailJFrame.builder() + .title("Zero Echo Char Test") + .testUI(ZeroEchoCharTest::new) + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 1) + .columns(40) + .build() + .awaitAndCheck(); + } +} diff --git a/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java b/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java index 02e7a890d83e4..78043cb5abdf4 100644 --- a/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java +++ b/test/jdk/java/awt/event/KeyEvent/FunctionKeyTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1998, 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 @@ -31,6 +31,18 @@ import java.awt.Robot; import java.awt.TextArea; import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicReference; + +import static java.awt.Event.KEY_ACTION; +import static java.awt.Event.KEY_ACTION_RELEASE; +import static java.util.concurrent.TimeUnit.SECONDS; /* * @test @@ -39,35 +51,38 @@ * @key headful */ -public class FunctionKeyTest { - private static FunctionKeyTester frame; +public final class FunctionKeyTest { + private static Frame frame; private static Robot robot; - static volatile boolean keyPressReceived; - static volatile boolean keyReleaseReceived; + private static final CyclicBarrier keyPress = new CyclicBarrier(2); + private static final CyclicBarrier keyRelease = new CyclicBarrier(2); - static final StringBuilder failures = new StringBuilder(); + private static final CountDownLatch frameActivated = new CountDownLatch(1); - private static void testKey(int keyCode, String keyText) { - keyPressReceived = false; - keyReleaseReceived = false; + private static final List failures = new ArrayList<>(4); + private static final AtomicReference edtException = new AtomicReference<>(); + private static void testKey(int keyCode, String keyText) throws Exception { robot.keyPress(keyCode); - - if (!keyPressReceived) { - failures.append(keyText).append(" key press is not received\n"); + try { + keyPress.await(2, SECONDS); + } catch (TimeoutException e) { + keyPress.reset(); + failures.add(new Error(keyText + " key press is not received", e)); } robot.keyRelease(keyCode); - - if (!keyReleaseReceived) { - failures.append(keyText).append(" key release is not received\n"); + try { + keyRelease.await(2, SECONDS); + } catch (TimeoutException e) { + keyRelease.reset(); + failures.add(new Error(keyText + " key release is not received", e)); } } public static void main(String[] args) throws Exception { robot = new Robot(); - robot.setAutoWaitForIdle(true); robot.setAutoDelay(150); try { @@ -75,11 +90,20 @@ public static void main(String[] args) throws Exception { frame = new FunctionKeyTester(); frame.setSize(200, 200); frame.setLocationRelativeTo(null); + frame.addWindowListener(new WindowAdapter() { + @Override + public void windowActivated(WindowEvent e) { + System.out.println("frame.windowActivated"); + frameActivated.countDown(); + } + }); frame.setVisible(true); }); - robot.waitForIdle(); - robot.delay(1000); + if (!frameActivated.await(2, SECONDS)) { + throw new Error("Frame wasn't activated"); + } + robot.delay(100); testKey(KeyEvent.VK_F11, "F11"); testKey(KeyEvent.VK_F12, "F12"); @@ -91,46 +115,69 @@ public static void main(String[] args) throws Exception { }); } - if (failures.isEmpty()) { - System.out.println("Passed"); - } else { - throw new RuntimeException(failures.toString()); + if (!failures.isEmpty()) { + System.err.println("Failures detected:"); + failures.forEach(System.err::println); + if (edtException.get() != null) { + System.err.println("\nException on EDT:"); + edtException.get().printStackTrace(); + } + System.err.println(); + throw new RuntimeException("Test failed: " + failures.get(0).getMessage(), + failures.get(0)); } - } -} -class FunctionKeyTester extends Frame { - Label l = new Label ("NULL"); - Button b = new Button(); - TextArea log = new TextArea(); - - FunctionKeyTester() { - super("Function Key Test"); - this.setLayout(new BorderLayout()); - this.add(BorderLayout.NORTH, l); - this.add(BorderLayout.SOUTH, b); - this.add(BorderLayout.CENTER, log); - log.setFocusable(false); - log.setEditable(false); - l.setBackground(Color.red); - setSize(200, 200); + if (edtException.get() != null) { + throw new RuntimeException("Test failed because of exception on EDT", + edtException.get()); + } } - public boolean handleEvent(Event e) { - String message = "e.id=" + e.id + "\n"; - System.out.print(message); - log.append(message); - - switch (e.id) { - case 403 -> FunctionKeyTest.keyPressReceived = true; - case 404 -> FunctionKeyTest.keyReleaseReceived = true; + private static final class FunctionKeyTester extends Frame { + Label l = new Label ("NULL"); + Button b = new Button("button"); + TextArea log = new TextArea(); + + FunctionKeyTester() { + super("Function Key Test"); + this.setLayout(new BorderLayout()); + this.add(BorderLayout.NORTH, l); + this.add(BorderLayout.SOUTH, b); + this.add(BorderLayout.CENTER, log); + log.setFocusable(false); + log.setEditable(false); + l.setBackground(Color.red); + setSize(200, 200); } - return super.handleEvent(e); - } + @Override + @SuppressWarnings("deprecation") + public boolean handleEvent(Event e) { + String message = "e.id=" + e.id + "\n"; + System.out.print(message); + log.append(message); + + try { + switch (e.id) { + case KEY_ACTION + -> keyPress.await(); + case KEY_ACTION_RELEASE + -> keyRelease.await(); + } + } catch (Exception ex) { + if (!edtException.compareAndSet(null, ex)) { + edtException.get().addSuppressed(ex); + } + } - public boolean keyDown(Event e, int key) { - l.setText("e.key=" + Integer.valueOf(e.key).toString()); - return false; + return super.handleEvent(e); + } + + @Override + @SuppressWarnings("deprecation") + public boolean keyDown(Event e, int key) { + l.setText("e.key=" + e.key); + return false; + } } } diff --git a/test/jdk/java/awt/event/KeyEvent/KeyTyped/Numpad1KeyTyped.java b/test/jdk/java/awt/event/KeyEvent/KeyTyped/Numpad1KeyTyped.java new file mode 100644 index 0000000000000..a944be855810a --- /dev/null +++ b/test/jdk/java/awt/event/KeyEvent/KeyTyped/Numpad1KeyTyped.java @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2002, 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.Frame; +import java.awt.Robot; +import java.awt.TextField; +import java.awt.Toolkit; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.KeyListener; +import java.util.concurrent.CountDownLatch; + +import jdk.test.lib.Platform; + +import static java.util.concurrent.TimeUnit.SECONDS; + +/* + * @test + * @bug 4724007 + * @key headful + * @summary Tests that KeyTyped events are fired for the Numpad1 key + * @library /test/lib + * @build jdk.test.lib.Platform + * @run main Numpad1KeyTyped + */ +public final class Numpad1KeyTyped extends FocusAdapter implements KeyListener { + + private static final String ORIGINAL = "0123456789"; + private static final String EXPECTED = "10123456789"; + + private final CountDownLatch typedNum1 = new CountDownLatch(1); + private final CountDownLatch focusGained = new CountDownLatch(1); + + public static void main(String[] args) throws Exception { + Numpad1KeyTyped test = new Numpad1KeyTyped(); + test.start(); + } + + private void start() throws Exception { + Toolkit toolkit = Toolkit.getDefaultToolkit(); + Boolean oldState = null; + + Robot robot = new Robot(); + robot.setAutoDelay(100); + + Frame frame = new Frame("Numpad1KeyTyped"); + TextField tf = new TextField(ORIGINAL, 20); + frame.add(tf); + tf.addKeyListener(this); + + tf.addFocusListener(this); + + frame.setSize(300, 100); + frame.setLocationRelativeTo(null); + frame.setVisible(true); + tf.requestFocusInWindow(); + + if (!focusGained.await(2, SECONDS)) { + throw new RuntimeException("TextField didn't receive focus"); + } + robot.waitForIdle(); + + try { + // Move cursor to start of TextField + robot.keyPress(KeyEvent.VK_HOME); + robot.keyRelease(KeyEvent.VK_HOME); + robot.waitForIdle(); + + if (Platform.isLinux()) { + // Press but don't release NumLock + robot.keyPress(KeyEvent.VK_NUM_LOCK); + } + if (Platform.isWindows()) { + oldState = toolkit.getLockingKeyState(KeyEvent.VK_NUM_LOCK); + toolkit.setLockingKeyState(KeyEvent.VK_NUM_LOCK, true); + } + + // Press and release Numpad-1 + robot.keyPress(KeyEvent.VK_NUMPAD1); + robot.keyRelease(KeyEvent.VK_NUMPAD1); + + if (!typedNum1.await(2, SECONDS)) { + throw new RuntimeException("TextField didn't receive keyTyped('1') - too slow"); + } + + final String text = tf.getText(); + if (!text.equals(EXPECTED)) { + throw new RuntimeException("Test FAILED: wrong string '" + + text + "' vs " + + "expected '" + EXPECTED + "'"); + } + System.out.println("Test PASSED"); + } finally { + if (Platform.isLinux()) { + // "release" + "press and release" NumLock to disable numlock + robot.keyRelease(KeyEvent.VK_NUM_LOCK); + robot.keyPress(KeyEvent.VK_NUM_LOCK); + robot.keyRelease(KeyEvent.VK_NUM_LOCK); + } + if (oldState != null) { + toolkit.setLockingKeyState(KeyEvent.VK_NUM_LOCK, oldState); + } + + frame.dispose(); + } + } + + @Override + public void focusGained(FocusEvent e) { + System.out.println("tf.focusGained"); + focusGained.countDown(); + } + + @Override + public void keyPressed(KeyEvent evt) { + printKey(evt); + } + + @Override + public void keyTyped(KeyEvent evt) { + printKey(evt); + + int keychar = evt.getKeyChar(); + if (keychar == '1') { + typedNum1.countDown(); + } + } + + @Override + public void keyReleased(KeyEvent evt) { + printKey(evt); + System.out.println(); + } + + private static void printKey(KeyEvent evt) { + int id = evt.getID(); + if (id != KeyEvent.KEY_TYPED + && id != KeyEvent.KEY_PRESSED + && id != KeyEvent.KEY_RELEASED) { + + System.out.println("Other Event"); + return; + } + + System.out.println("params= " + evt.paramString() + " \n" + + "KeyChar: " + evt.getKeyChar() + " = " + (int) evt.getKeyChar() + + " KeyCode: " + evt.getKeyCode() + + " Modifiers: " + evt.getModifiersEx()); + + if (evt.isActionKey()) { + System.out.println(" Action Key"); + } + + System.out.println("keyText= " + KeyEvent.getKeyText(evt.getKeyCode()) + "\n"); + } + +} diff --git a/test/jdk/java/awt/image/BufferedImage/GrayAATextTest.java b/test/jdk/java/awt/image/BufferedImage/GrayAATextTest.java new file mode 100644 index 0000000000000..a484dd392eb03 --- /dev/null +++ b/test/jdk/java/awt/image/BufferedImage/GrayAATextTest.java @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2000, 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 + * @bug 4309915 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Check that Antialiased text drawn on a BYTE_GRAY image + * resolves the color correctly + * @run main/manual GrayAATextTest + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Panel; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; + +public class GrayAATextTest extends Panel { + + public static final int WIDTH = 600; + public static final int HEIGHT = 200; + + private static final String INSTRUCTIONS = """ + All of the strings in a given column should be drawn + in the same color. If the bug is present, then the + Antialiased strings will all be of a fixed color that + is not the same as the other strings in their column."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("GrayAATextTest Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(GrayAATextTest::createTestUI) + .build() + .awaitAndCheck(); + } + + public void paint(Graphics g) { + BufferedImage bi = new BufferedImage(WIDTH, HEIGHT, + BufferedImage.TYPE_BYTE_GRAY); + Graphics2D g2d = bi.createGraphics(); + g2d.setFont(new Font("Helvetica", Font.PLAIN, 24)); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, WIDTH / 2, HEIGHT); + drawText(g2d, Color.black, "Black", 25); + drawText(g2d, Color.lightGray, "Light Gray", 175); + g2d.setColor(Color.black); + g2d.fillRect(WIDTH / 2, 0, WIDTH / 2, HEIGHT); + drawText(g2d, Color.white, "White", 325); + drawText(g2d, Color.lightGray, "Light Gray", 475); + g2d.dispose(); + g.drawImage(bi, 0, 0, null); + } + + public void drawText(Graphics2D g2d, Color c, String colorname, int x) { + g2d.setColor(c); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + g2d.drawString(colorname, x, 50); + g2d.drawString("Aliased", x, 100); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_ON); + g2d.drawString("Antialiased", x, 150); + } + + public Dimension getPreferredSize() { + return new Dimension(WIDTH, HEIGHT); + } + + private static Frame createTestUI() { + Frame f = new Frame("GrayAATextTest Frame"); + f.add(new GrayAATextTest()); + f.setSize(WIDTH, HEIGHT); + return f; + } +} diff --git a/test/jdk/java/awt/image/GrayAlpha.java b/test/jdk/java/awt/image/GrayAlpha.java new file mode 100644 index 0000000000000..cf477c2638503 --- /dev/null +++ b/test/jdk/java/awt/image/GrayAlpha.java @@ -0,0 +1,175 @@ +/* + * 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. + */ + +/* + * @test + * @bug 4243044 + * @summary This test should show two windows filled with checker + * board pattern. The transparency should runs from left to right from + * total transparent to total opaque. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual GrayAlpha + */ + +import java.util.List; +import java.awt.Frame; +import java.awt.color.ColorSpace; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.Point; +import java.awt.Panel; +import java.awt.Transparency; +import java.awt.Window; + +public class GrayAlpha extends Panel { + + private static final String INSTRUCTIONS = """ + This test should show two windows filled with checker board + vpattern. The transparency should runs from left to right from + totally transparent to totally opaque. If either the pattern or + the transparency is not shown correctly, click Fail, otherwise + click Pass."""; + + BufferedImage bi; + AffineTransform identityTransform = new AffineTransform(); + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("GrayAlpha Instructions") + .instructions(INSTRUCTIONS) + .rows((int)INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(GrayAlpha::createTestUI) + .build() + .awaitAndCheck(); + } + + + public GrayAlpha(int width, int height, + boolean hasAlpha, boolean isAlphaPremultiplied, + boolean useRGB) { + boolean isAlphaPremuliplied = true; + int bands = useRGB ? 3 : 1; + bands = hasAlpha ? bands + 1 : bands; + + ColorSpace cs = useRGB ? + ColorSpace.getInstance(ColorSpace.CS_sRGB) : + ColorSpace.getInstance(ColorSpace.CS_GRAY); + int transparency = hasAlpha ? + Transparency.TRANSLUCENT : Transparency.OPAQUE; + int[] bits = new int[bands]; + for (int i = 0; i < bands; i++) { + bits[i] = 8; + } + + ColorModel cm = new ComponentColorModel(cs, + bits, + hasAlpha, + isAlphaPremultiplied, + transparency, + DataBuffer.TYPE_BYTE); + WritableRaster wr = + Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, + width, height, bands, + new Point(0, 0)); + + for (int b = 0; b < bands; b++) { + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x++) { + int s; + + if (b != bands - 1 || !hasAlpha) { + // Gray band(s), fill with a checkerboard pattern + if (((x / 10) % 2) == ((y / 10) % 2)) { + s = 255; + } else { + s = 0; + } + if (isAlphaPremultiplied) { + int alpha = (x*255)/(width - 1); + s = (s*alpha)/255; + } + } else { + // Alpha band, increase opacity left to right + s = (x*255)/(width - 1); + } + + wr.setSample(x, y, b, s); + } + } + } + + this.bi = new BufferedImage(cm, wr, isAlphaPremultiplied, null); + } + + public Dimension getPreferredSize() { + return new Dimension(bi.getWidth(), bi.getHeight()); + } + + public void paint(Graphics g) { + if (bi != null) { + ((Graphics2D)g).drawImage(bi, 0, 0, null); + } + } + + public static Frame makeFrame(String title, + int x, int y, int width, int height, + boolean hasAlpha, + boolean isAlphaPremultiplied, + boolean useRGB) { + Frame f = new Frame(title); + f.add(new GrayAlpha(width, height, + hasAlpha, isAlphaPremultiplied, useRGB)); + f.pack(); + f.setLocation(x, y); + return f; + } + + private static List createTestUI() { + int width = 200; + int height = 200; + + int x = 100; + int y = 100; + + Frame f1 = makeFrame("Gray (non-premultiplied)", + x, y, width, height, + true, false, false); + x += width + 20; + + Frame f2 = makeFrame("Gray (premultiplied)", + x, y, width, height, + true, true, false); + + return List.of(f1, f2); + } +} diff --git a/test/jdk/java/awt/image/ImageOffsetTest.java b/test/jdk/java/awt/image/ImageOffsetTest.java new file mode 100644 index 0000000000000..c1d4c3931de91 --- /dev/null +++ b/test/jdk/java/awt/image/ImageOffsetTest.java @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2000, 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 + * @bug 4259548 + * @summary tests that MemoryImageSource correctly handles images with offsets + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual ImageOffsetTest + */ + +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Panel; +import java.awt.Toolkit; +import java.awt.image.ColorModel; +import java.awt.image.IndexColorModel; +import java.awt.image.MemoryImageSource; + +public class ImageOffsetTest { + + static int height = 100; + static int width = 100; + static int levels = 3; + static IndexColorModel cm; + static Image image; + static boolean first = true; + + static byte[] db = new byte[height * width * levels] ; + + private static final String INSTRUCTIONS = """ + If on the appeared 'Test frame' all color squares are of one color + test failed, otherwise it's passed."""; + + public static void main(String[] args) throws Exception { + PassFailJFrame.builder() + .title("ImageOffsetTest") + .instructions(INSTRUCTIONS) + .rows((int) INSTRUCTIONS.lines().count() + 2) + .columns(35) + .testUI(ImageOffsetTest::createUI) + .build() + .awaitAndCheck(); + } + + private static Frame createUI() { + Frame frame = new Frame("ImageOffset Frame"); + frame.add(new Panel() { + public void paint(Graphics g) { + for ( int i=0 ; i<3 ; i++ ) { + g.drawImage( + generateBuggyImage(i * width * height), 10 + i * 110, 10, null); + } + } + }); + frame.setSize(400, 200); + frame.setLocation(300, 200); + createColorModel(); + int l = 0; + for (int k = 0; k < levels; k++) { + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + if( k == 0) { + db[l] = (byte)(70 & 0xff) ; + } + if (k == 1) { + db[l] = (byte)(150 & 0xff) ; + } + if (k == 2) { + db[l] = (byte)(230 & 0xff) ; + } + l++ ; + } + } + } + return frame; + } + + private static void createColorModel() { + byte[] red = new byte[256]; + byte[] green = new byte[256]; + byte[] blue = new byte[256]; + + for (int i = 0; i < 256; i++) { + red[i] = (byte)(i & 0xff); + //green[i] = (byte)( i & 0xff ) ; + blue[i] = (byte)( i & 0xff ) ; + //commented out green so I could get purple + } + + cm = new IndexColorModel( 8, 256, red, green, blue ) ; + } + + private static Image generateBuggyImage(int offset) { + // Initialize the database, Three slices, different shades of grey + // Here the image is created using the offset, + return Toolkit.getDefaultToolkit().createImage( + new MemoryImageSource(width, height, (ColorModel)cm, + db, offset, width)); + } +} diff --git a/test/jdk/java/awt/image/TransformImage.java b/test/jdk/java/awt/image/TransformImage.java new file mode 100644 index 0000000000000..30af3d27f55c0 --- /dev/null +++ b/test/jdk/java/awt/image/TransformImage.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4090743 + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @summary Make sure that there is no garbage drawn on the rotated image + * @run main/manual TransformImage + */ + +import java.net.URL; +import java.net.MalformedURLException; +import java.awt.Canvas; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.geom.AffineTransform; +import java.awt.Image; +import java.awt.image.ImageObserver; +import java.awt.MediaTracker; +import java.awt.Toolkit; + +public class TransformImage extends Canvas { + static Image image; + + private static final String INSTRUCTIONS = """ + The rotated image should be drawn without garbage."""; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("TransformImage Instructions") + .instructions(INSTRUCTIONS) + .rows(5) + .columns(35) + .testUI(TransformImage::createTestUI) + .build() + .awaitAndCheck(); + } + + private static Frame createTestUI() { + Frame f = new Frame(); + String dir = System.getProperty("test.src"); + String sep = System.getProperty("file.separator"); + if (dir == null) { + dir = "."; + } + image = Toolkit.getDefaultToolkit().getImage(dir+sep+"duke.gif"); + f.add(new TransformImage()); + + f.pack(); + return f; + } + + public Dimension getPreferredSize() { + return new Dimension (256, 256); + } + + public Dimension getMinimumSize() { + return getPreferredSize(); + } + + public void paint(Graphics g) { + int w, h; + java.awt.Graphics2D g2d = (Graphics2D) g; + AffineTransform at = new AffineTransform(); + + MediaTracker mt = new MediaTracker(this); + mt.addImage(image, 0); + try { + mt.waitForAll(); + } catch (InterruptedException e) { + System.err.println("can't track"); + return; + } + w = image.getWidth(this); + h = image.getHeight(this); + g2d.drawImage(image, 0, 0, this); + g2d.drawRect(0, 0, w, h); + + double rad = .5; + at.rotate(-rad); + g2d.setTransform(at); + g2d.drawImage(image, 0, 100, this); + g2d.drawRect(0, 100, w, h); + } +} diff --git a/test/jdk/java/awt/image/duke.gif b/test/jdk/java/awt/image/duke.gif new file mode 100644 index 0000000000000..ed32e0ff79b05 Binary files /dev/null and b/test/jdk/java/awt/image/duke.gif differ diff --git a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java index 594e97152a55c..3a142c716b199 100644 --- a/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java +++ b/test/jdk/java/awt/regtesthelpers/PassFailJFrame.java @@ -74,6 +74,7 @@ import javax.swing.text.html.StyleSheet; import static java.util.Collections.unmodifiableList; +import static javax.swing.BorderFactory.createEmptyBorder; import static javax.swing.SwingUtilities.invokeAndWait; import static javax.swing.SwingUtilities.isEventDispatchThread; @@ -158,7 +159,7 @@ *
  • the title of the instruction UI,
  • *
  • the timeout of the test,
  • *
  • the size of the instruction UI via rows and columns, and
  • - *
  • to add a log area
  • , + *
  • to add a log area,
  • *
  • to enable screenshots.
  • * */ @@ -348,11 +349,9 @@ private PassFailJFrame(final Builder builder) builder.positionWindows .positionTestWindows(unmodifiableList(builder.testWindows), builder.instructionUIHandler)); - } else if (builder.testWindows.size() == 1) { + } else { Window window = builder.testWindows.get(0); positionTestWindow(window, builder.position); - } else { - positionTestWindow(null, builder.position); } } showAllWindows(); @@ -501,6 +500,7 @@ private static JTextComponent configurePlainText(String instructions, JTextArea text = new JTextArea(instructions, rows, columns); text.setLineWrap(true); text.setWrapStyleWord(true); + text.setBorder(createEmptyBorder(4, 4, 4, 4)); return text; } @@ -1111,9 +1111,10 @@ public static void forceFail(String reason) { /** * Adds a {@code message} to the log area, if enabled by - * {@link Builder#logArea()} or {@link Builder#logArea(int)}. + * {@link Builder#logArea() logArea()} or + * {@link Builder#logArea(int) logArea(int)}. * - * @param message to log + * @param message the message to log */ public static void log(String message) { System.out.println("PassFailJFrame: " + message); @@ -1122,7 +1123,8 @@ public static void log(String message) { /** * Clears the log area, if enabled by - * {@link Builder#logArea()} or {@link Builder#logArea(int)}. + * {@link Builder#logArea() logArea()} or + * {@link Builder#logArea(int) logArea(int)}. */ public static void logClear() { System.out.println("\nPassFailJFrame: log cleared\n"); @@ -1131,7 +1133,9 @@ public static void logClear() { /** * Replaces the log area content with provided {@code text}, if enabled by - * {@link Builder#logArea()} or {@link Builder#logArea(int)}. + * {@link Builder#logArea() logArea()} or + * {@link Builder#logArea(int) logArea(int)}. + * * @param text new text for the log area */ public static void logSet(String text) { @@ -1182,11 +1186,45 @@ public Builder testTimeOut(long testTimeOut) { return this; } + /** + * Sets the number of rows for displaying the instruction text. + * The default value is the number of lines in the text plus 1: + * {@code ((int) instructions.lines().count() + 1)}. + * + * @param rows the number of rows for instruction text + * @return this builder + */ public Builder rows(int rows) { this.rows = rows; return this; } + private int getDefaultRows() { + return (int) instructions.lines().count() + 1; + } + + /** + * Adds a certain number of rows for displaying the instruction text. + * + * @param rowsAdd the number of rows to add to the number of rows + * @return this builder + * @see #rows + */ + public Builder rowsAdd(int rowsAdd) { + if (rows == 0) { + rows = getDefaultRows(); + } + rows += rowsAdd; + + return this; + } + + /** + * Sets the number of columns for displaying the instruction text. + * + * @param columns the number of columns for instruction text + * @return this builder + */ public Builder columns(int columns) { this.columns = columns; return this; @@ -1481,7 +1519,7 @@ private void validate() { } if (rows == 0) { - rows = ROWS; + rows = getDefaultRows(); } if (columns == 0) { diff --git a/test/jdk/java/lang/Math/HyperbolicTests.java b/test/jdk/java/lang/Math/HyperbolicTests.java index cf583ed7b5f27..4534396ee06dd 100644 --- a/test/jdk/java/lang/Math/HyperbolicTests.java +++ b/test/jdk/java/lang/Math/HyperbolicTests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2023, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -969,6 +969,400 @@ static int testTanh() { failures += testTanhCaseWithUlpDiff(d, 1.0, 2.5); } + failures += testTanhAdditionalTests(); + + return failures; + } + + /** + * Test accuracy of {Math, StrictMath}.tanh using quad precision + * tanh implementation as the reference. There are additional tests. + * The specified accuracy is 2.5 ulps. + * + */ + static int testTanhAdditionalTests() { + int failures = 0; + /* + * Array elements below are generated using a quad precision tanh + * implementation (libquadmath). Rounded to a double, the quad result + * *should* be correctly rounded, unless we are quite unlucky. + * Assuming the quad value is a correctly rounded double, the + * allowed error is 3.0 ulps instead of 2.5 since the quad + * value rounded to double can have its own 1/2 ulp error. + */ + double[][] testCases = { + // x tanh(x) + {1.09951162777600024414062500000000000e+12, 1.00000000000000000000000000000000000e+00}, + {1.56250000000000416333634234433702659e-02, 1.56237285584089068255495133849899136e-02}, + {1.61254882812500000000000000000000000e+01, 9.99999999999980293529906376885389048e-01}, + {2.53165043529127054000582575099542737e-01, 2.47891535884497437358843835970604812e-01}, + {2.05669906337718799704816774465143681e+00, 9.67821952180774991463712302156014956e-01}, + {8.73243486124784240587359818164259195e+00, 9.99999947984421044859570034536492937e-01}, + {1.35302734375000000000000000000000000e+00, 8.74765946489987955543753077657414741e-01}, + {7.51299319580434721288497712521348149e-01, 6.35923468395323117288273690770900477e-01}, + {9.53088818012631927567568368431238923e-02, 9.50213381512267711017656118902912332e-02}, + {7.64443165964961757197215774795040488e-01, 6.43686625696507143760198874608796949e-01}, + {9.80772770147126660145175947036477737e-02, 9.77640088885469645387119927980991050e-02}, + {8.00000000000000044408920985006261617e-01, 6.64036770267848988511881426480887109e-01}, + {6.58800443825626694943631278533757722e-03, 6.58790912948844334160953310959647563e-03}, + {3.50634723606509357551885841530747712e+00, 9.98200861366828007281302037717336212e-01}, + {8.80951107580675074615328412619419396e-01, 7.06895478355484050029724917425086249e-01}, + {9.41693953354077795125931515940465033e-01, 7.35999567964351009171211613664845735e-01}, + {4.86714106743433794211028953213826753e-01, 4.51604571680788935707314000261162601e-01}, + {4.99999999970896114032115065128891729e-01, 4.62117157237121073362068671381593592e-01}, + {1.27999999999999971578290569595992565e+02, 1.00000000000000000000000000000000000e+00}, + {1.00000000000000022204460492503130808e+00, 7.61594155955764981372495044941331753e-01}, + {1.09951162777600024414062500000000000e+12, 1.00000000000000000000000000000000000e+00}, + {5.00000000000000777156117237609578297e-01, 4.62117157260010369694985045764006657e-01}, + {3.90625000000001474514954580286030250e-03, 3.90623013190635482599726614938805467e-03}, + {1.56250000000000659194920871186695877e-02, 1.56237285584089311057499113400637264e-02}, + {1.25000000000001332267629550187848508e-01, 1.24353001771597519720531117125519878e-01}, + {1.56250000000005169475958410885141348e-02, 1.56237285584093820237573019342883109e-02}, + {2.00000000000022737367544323205947876e+00, 9.64027580075832948084133680630298643e-01}, + {6.25000000000080352391407245704613160e-02, 6.24187467475205184231888372622987839e-02}, + {2.50000000000049737991503207013010979e-01, 2.44918662403755883728363950973251081e-01}, + {2.50000000000454747350886464118957520e-01, 2.44918662404136598540089724354621762e-01}, + {7.81250000001537658889105841808486730e-03, 7.81234105817638947180855590780540396e-03}, + {8.00000000002179945113311987370252609e+00, 9.99999774929675899622836792366347278e-01}, + {8.00000000002182787284255027770996094e+00, 9.99999774929675899635630557632573807e-01}, + {1.00000000004506106598967107856879011e+00, 7.61594155974689379640247120538425632e-01}, + {5.00000000024432678102925819985102862e-01, 4.62117157279224782806433798595181278e-01}, + {5.00000000124148025193449029757175595e-01, 4.62117157357645691462301850285961295e-01}, + {1.25000000043655745685100555419921875e-01, 1.24353001814576875736126314329404676e-01}, + {1.56250130385160446166992187500000000e-02, 1.56237415937421937398207048034470765e-02}, + {6.25000596046447753906250000000000000e-02, 6.24188061199314157260056878713262148e-02}, + {6.25001570879248902201652526855468750e-02, 6.24189032234056148184566765458350515e-02}, + {3.12509536743164062500000000000000000e-02, 3.12407841896026978197614959195842857e-02}, + {1.00024414062500000000000000000000000e+00, 7.61696669690972358277739369649969500e-01}, + {1.25091552734375000000000000000000000e-01, 1.24443137738349286849917747910445080e-01}, + {6.25703578334750876166481248219497502e-02, 6.24888301519391612116796252071905868e-02}, + {2.52525252525252597024518763646483421e-01, 2.47290965006585965880182136581880733e-01}, + {1.00000000164410457817454336293394590e-03, 9.99999668310902934017090322313224382e-04}, + {1.00000000966720672609944209341392707e-03, 9.99999676333997058845099107943491685e-04}, + {5.13687551499984795810860305209644139e-01, 4.72813376851263299460550751434331149e-01}, + {1.03125000000000000000000000000000000e+00, 7.74409187434213568286703209738132986e-01}, + {1.03372912114974835340319714305223897e+00, 7.75399652279487427958938283855319050e-01}, + {8.73243486124791523650401359191164374e+00, 9.99999947984421044867146689152891277e-01}, + {5.46364074509520181166521979321260005e-01, 4.97790203319363272413440879555555135e-01}, + {5.48776992118357842542764046811498702e-01, 4.99603030846724465253358333732665160e-01}, + {8.62884521484375000000000000000000000e-03, 8.62863106199946057455229821459862778e-03}, + {5.56840723899044820477399753144709393e-01, 5.05629619734278492036257594911833276e-01}, + {1.12042968912429174999090264464030042e+00, 8.07718324543002512898290101804260243e-01}, + {2.80761718750000000000000000000000000e-01, 2.73609921989813966516244201735889906e-01}, + {4.50982142857161694138312668655999005e+00, 9.99758010610690750512553927515350523e-01}, + {1.79803946803892764072507759465224808e-02, 1.79784572761372499903768063141254578e-02}, + {2.90674624105783541150316295897937380e-01, 2.82755618405959946459876962574827861e-01}, + {3.00000000019552404140199541870970279e-01, 2.91312612469484033539387970973996561e-01}, + {1.52306844600212459850396840010944288e-01, 1.51139964502163284820786391222343666e-01}, + {1.21913138136517762433186362613923848e+00, 8.39397762830401796350294214789399315e-01}, + {1.91612901016097944562055488404439529e-02, 1.91589453912240029886209020645693670e-02}, + {1.23194037796136601770058405236341059e+00, 8.43141232466373734055029303451281784e-01}, + {5.14544145441922751160745974630117416e+00, 9.99932120037417992977353814124626761e-01}, + {1.29608715898613313655118872702587396e+00, 8.60712461444305632100271902930674052e-01}, + {1.35302734375000000000000000000000000e+00, 8.74765946489987955543753077657414741e-01}, + {6.89141205308152926534148718928918242e-01, 5.97430012402391408227990740295335202e-01}, + {2.16702398900134561576802383342510439e-02, 2.16668484172600518601166701940771309e-02}, + {6.95330121814107471323040954302996397e-01, 6.01395252733578654705526153849150843e-01}, + {1.70127028180982076566857275068400668e-04, 1.70127026539641570641832179464678521e-04}, + {6.98731899876564921392230189667316154e-01, 6.03562246839061712657431798989209285e-01}, + {2.82308042901865396956395670713391155e+00, 9.92962754889608618611084237181745775e-01}, + {8.85009765625000000000000000000000000e-02, 8.82706391518277914218106043840064600e-02}, + {1.44086021505376304929768593865446746e+00, 8.93870759190524111186764508137227647e-01}, + {4.52708479240923750142044923450157512e-02, 4.52399464814195843886615749285771251e-02}, + {7.42434201630502221824770003877347335e-01, 6.30613596749571014884527941122811076e-01}, + {7.47314453125000000000000000000000000e-01, 6.33544059591028741704251380359792317e-01}, + {2.33572976827208893257914468222224968e-02, 2.33530509808936286709795071423335732e-02}, + {7.51392746195329142011587464367039502e-01, 6.35979110106607807348963004903609067e-01}, + {7.51649175412362091641682582121575251e-01, 6.36131796640758591543062918907122080e-01}, + {7.62560692649938864917658065678551793e-01, 6.42582785959772486552828548950126373e-01}, + {7.64660852335945273594575155584607273e-01, 6.43814099671361386286313072270915932e-01}, + {1.92871093750000000000000000000000000e-01, 1.90514597602311764623059750704793759e-01}, + {2.43864313521849479515779535176989157e-02, 2.43815983142663741885939851467013521e-02}, + {3.97705078125000000000000000000000000e-01, 3.77983627858614640283948547303348236e-01}, + {7.98034667968750000000000000000000000e-01, 6.62936606884708330125541187161682941e-01}, + {7.99316406250000000000000000000000000e-01, 6.63654430152659513562528989372441102e-01}, + {1.99890136718750000000000000000000000e-01, 1.97269734600247465099938891830640889e-01}, + {2.00000000008910994164779140191967599e-01, 1.97375320233467849151455260287892058e-01}, + {4.00000000093461316463816501709516160e-01, 3.79948962335194012629557116519596150e-01}, + {2.00000000069810862646235705142316874e-01, 1.97375320291995240418209079080646997e-01}, + {1.00000000056612609045103567950718571e-01, 9.96679946810060529704707312198636589e-02}, + {1.00000000080404896629637789828848327e-01, 9.96679947045619948897444345018478492e-02}, + {1.66666666666666696272613990004174411e+00, 9.31109608667577693190680177920119455e-01}, + {1.31034851074218750000000000000000000e-02, 1.31027351970209980614612589861988504e-02}, + {8.43444227005861080215254332870244980e-01, 6.87629045782656322925865941652078512e-01}, + {4.25596815032856623517432126391213387e-01, 4.01634947321531793299729470086813678e-01}, + {8.54614885269050605920426733064232394e-01, 6.93472710492835200064966331725774025e-01}, + {8.63777419830865200722769259300548583e-01, 6.98198780318331041148483592329099127e-01}, + {2.70117449276632004551146337689715438e-02, 2.70051772786722224566765342032635559e-02}, + {2.16282487792377908775165451515931636e-01, 2.12971988592557031781365419455581001e-01}, + {1.73204653003120601084674490266479552e+00, 9.39297315789076214802641716736658105e-01}, + {2.71436010781672190650404274947504746e-02, 2.71369367992428389623549774823710978e-02}, + {8.69092640155437079485523099720012397e-01, 7.00912831250687651307196017605464473e-01}, + {2.78015136718750000000000000000000000e-02, 2.77943530651526982827985645341156701e-02}, + {9.10156250000000000000000000000000000e-01, 7.21207240669352050307412688531998165e-01}, + {2.27787862235060922788676407435559668e-01, 2.23928183342045426304404589794035157e-01}, + {5.71524498377538048288215577485971153e-02, 5.70903033991663026980553749418981725e-02}, + {3.66406250000000000000000000000000000e+00, 9.98687254335130669671645868977829517e-01}, + {5.72863132979952241474741470028675394e-02, 5.72237295373843844708720164610859507e-02}, + {1.15265335196343660095763539175095502e-01, 1.14757558082362397172277983632352767e-01}, + {9.22871508732805212460448274214286357e-01, 7.27253018562057912939305739474564638e-01}, + {1.44882202148437500000000000000000000e-02, 1.44872065663080247568859985337817684e-02}, + {2.33459472656250000000000000000000000e-01, 2.29308506606965514793638071915067313e-01}, + {4.67608948699241744328958247933769599e-01, 4.36265367328226513916944408221096440e-01}, + {2.34375000000000000000000000000000000e-01, 2.30175711032132981819570603563403063e-01}, + {2.93977526337722387672624080323657836e-02, 2.93892867747176836833509722656208701e-02}, + {1.89257812500000000000000000000000000e+00, 9.55597542193888546329823463414294394e-01}, + {2.95798696005085230698039566732404637e-02, 2.95712454656271068251835101101858187e-02}, + {1.89360756176453159937977943627629429e+00, 9.55686843743833788059988471898348142e-01}, + {4.74943000289441419337066463413066231e-01, 4.42184502480986035803118250513914071e-01}, + {4.76562500000000000000000000000000000e-01, 4.43486412595195826790440814160101630e-01}, + {9.59027831303091549131067949929274619e-01, 7.43842915769532264613887042424467929e-01}, + {3.09784640940728682456661857713697827e-02, 3.09685582448730820784897541732374591e-02}, + {1.98437499999999977795539507496869192e+00, 9.62906870975765387287608356129776957e-01}, + {9.97205648659918675313917901803506538e-01, 7.60418100316000600203658397859135661e-01}, + {3.90291213989257769131913100579822640e-03, 3.90289232268659551022766662201699736e-03}, + {3.90481948852539019131913100579822640e-03, 3.90479964225138860483705936617354227e-03}, + {3.12423706054687500000000000000000000e-02, 3.12322094954161727499363714231262395e-02}, + {3.90535406768321947598709975579822640e-03, 3.90533421325712750455622728849037270e-03}, + {7.81154632568359288263826201159645279e-03, 7.81138744204279466358299901763388375e-03}, + {1.24999789521095569511111023075500270e-01, 1.24352794547462473786771370350680283e-01}, + {9.99999444341875043384959553804947063e-01, 7.61593922593510941370556728778707492e-01}, + {9.99999895691871532044103787484345958e-01, 7.61594112149023829770882693858011645e-01}, + {2.49999998130078865399283927217766177e-01, 2.44918660645955495851244772320875652e-01}, + {2.49999998603016110321206610933586489e-01, 2.44918661090523528987141309434443089e-01}, + {4.99999999970896114032115065128891729e-01, 4.62117157237121073362068671381593592e-01}, + {9.99999999999829358721115113439736888e-01, 7.61594155955693223160706417649502130e-01}, + {3.12499999999979183318288278314867057e-02, 3.12398314460291771315638233977623908e-02}, + {6.24999999999973701592104191604448715e-02, 6.24187467475098948954758673929811576e-02}, + {9.99999999999998556710067987296497449e-01, 7.61594155955764281974719327416526334e-01}, + {1.27999999999999971578290569595992565e+02, 1.00000000000000000000000000000000000e+00}, + {3.44827586206896546938693859374325257e-02, 3.44690977543900329082306735053903756e-02}, + {6.89655172413793093877387718748650514e-02, 6.88563859490195017187269420471893052e-02}, + {1.03448275862068964081608157812297577e-01, 1.03080829858086020470241143281488892e-01}, + {1.37931034482758618775477543749730103e-01, 1.37062928881132531260309423128680656e-01}, + {1.72413793103448287347134737501619384e-01, 1.70725445282084714146447066718646674e-01}, + {2.06896551724137955918791931253508665e-01, 2.03994088403983264406130799853712156e-01}, + {2.41379310344827624490449125005397946e-01, 2.36798141876826809207868665407968027e-01}, + {2.75862068965517293062106318757287227e-01, 2.69071023201531202536913498454407638e-01}, + {3.10344827586206961633763512509176508e-01, 3.00750767242988858303859696730149916e-01}, + {3.44827586206896630205420706261065789e-01, 3.31780427497542984412066808006924260e-01}, + {3.79310344827586298777077900012955070e-01, 3.62108391409330839416919529705937418e-01}, + {4.13793103448275967348735093764844351e-01, 3.91688608393346163715111892758489641e-01}, + {4.48275862068965635920392287516733631e-01, 4.20480731486975012003415012347372452e-01}, + {4.82758620689655304492049481268622912e-01, 4.48450175615929701255698232730127770e-01}, + {5.17241379310344973063706675020512193e-01, 4.75568097261544496368767486763625886e-01}, + {5.51724137931034586124212637514574453e-01, 5.01811301809605377924874787743959204e-01}, + {5.86206896551724199184718600008636713e-01, 5.27162086020673527345538794213535134e-01}, + {6.20689655172413812245224562502698973e-01, 5.51608023880856575817362987825134405e-01}, + {6.55172413793103425305730524996761233e-01, 5.75141704579102279221464447290041163e-01}, + {6.89655172413793038366236487490823492e-01, 5.97760431534850182076591161239096491e-01}, + {7.24137931034482651426742449984885752e-01, 6.19465891301270655454827665546029664e-01}, + {7.58620689655172264487248412478948012e-01, 6.40263800834536321750527885396253899e-01}, + {7.93103448275861877547754374973010272e-01, 6.60163541092833363676687202005166905e-01}, + {8.27586206896551490608260337467072532e-01, 6.79177784255529339466238655218797135e-01}, + {8.62068965517241103668766299961134791e-01, 6.97322121077226884958095667604561029e-01}, + {8.96551724137930716729272262455197051e-01, 7.14614694054361357412620518070189428e-01}, + {9.31034482758620329789778224949259311e-01, 7.31075841220047215751737025073520835e-01}, + {9.65517241379309942850284187443321571e-01, 7.46727754527182387965057729340710925e-01}, + {9.99999999999999555910790149937383831e-01, 7.61594155955764701613384757931622516e-01}, + {1.26765060022822940149670320537600000e+30, 1.00000000000000000000000000000000000e+00}, + {1.33436905287182034855574634496000000e+30, 1.00000000000000000000000000000000000e+00}, + {1.40108750551541129561478948454400000e+30, 1.00000000000000000000000000000000000e+00}, + {1.46780595815900224267383262412800000e+30, 1.00000000000000000000000000000000000e+00}, + {1.53452441080259318973287576371200000e+30, 1.00000000000000000000000000000000000e+00}, + {1.60124286344618413679191890329600000e+30, 1.00000000000000000000000000000000000e+00}, + {1.66796131608977508385096204288000000e+30, 1.00000000000000000000000000000000000e+00}, + {1.73467976873336603091000518246400000e+30, 1.00000000000000000000000000000000000e+00}, + {1.80139822137695697796904832204800000e+30, 1.00000000000000000000000000000000000e+00}, + {1.86811667402054792502809146163200000e+30, 1.00000000000000000000000000000000000e+00}, + {1.93483512666413887208713460121600000e+30, 1.00000000000000000000000000000000000e+00}, + {2.00155357930772981914617774080000000e+30, 1.00000000000000000000000000000000000e+00}, + {2.06827203195132076620522088038400000e+30, 1.00000000000000000000000000000000000e+00}, + {2.13499048459491171326426401996800000e+30, 1.00000000000000000000000000000000000e+00}, + {2.20170893723850266032330715955200000e+30, 1.00000000000000000000000000000000000e+00}, + {2.26842738988209360738235029913600000e+30, 1.00000000000000000000000000000000000e+00}, + {2.33514584252568455444139343872000000e+30, 1.00000000000000000000000000000000000e+00}, + {2.40186429516927550150043657830400000e+30, 1.00000000000000000000000000000000000e+00}, + {2.46858274781286644855947971788800000e+30, 1.00000000000000000000000000000000000e+00}, + {2.53530120045645739561852285747200000e+30, 1.00000000000000000000000000000000000e+00}, + {1.60693804425899027554196209234116260e+60, 1.00000000000000000000000000000000000e+00}, + {1.69151373079893703825155926128281056e+60, 1.00000000000000000000000000000000000e+00}, + {1.77608941733888380096115643022445853e+60, 1.00000000000000000000000000000000000e+00}, + {1.86066510387883056367075359916610649e+60, 1.00000000000000000000000000000000000e+00}, + {1.94524079041877732638035076810775445e+60, 1.00000000000000000000000000000000000e+00}, + {2.02981647695872408908994793704940241e+60, 1.00000000000000000000000000000000000e+00}, + {2.11439216349867085179954510599105038e+60, 1.00000000000000000000000000000000000e+00}, + {2.19896785003861761450914227493269834e+60, 1.00000000000000000000000000000000000e+00}, + {2.28354353657856437721873944387434630e+60, 1.00000000000000000000000000000000000e+00}, + {2.36811922311851113992833661281599426e+60, 1.00000000000000000000000000000000000e+00}, + {2.45269490965845790263793378175764222e+60, 1.00000000000000000000000000000000000e+00}, + {2.53727059619840466534753095069929019e+60, 1.00000000000000000000000000000000000e+00}, + {2.62184628273835142805712811964093815e+60, 1.00000000000000000000000000000000000e+00}, + {2.70642196927829819076672528858258611e+60, 1.00000000000000000000000000000000000e+00}, + {2.79099765581824495347632245752423407e+60, 1.00000000000000000000000000000000000e+00}, + {2.87557334235819171618591962646588203e+60, 1.00000000000000000000000000000000000e+00}, + {2.96014902889813847889551679540753000e+60, 1.00000000000000000000000000000000000e+00}, + {3.04472471543808524160511396434917796e+60, 1.00000000000000000000000000000000000e+00}, + {3.12930040197803200431471113329082592e+60, 1.00000000000000000000000000000000000e+00}, + {3.21387608851797876702430830223247388e+60, 1.00000000000000000000000000000000000e+00}, + {1.07150860718626732094842504906000181e+301, 1.00000000000000000000000000000000000e+00}, + {1.12790379703817606470289337889334663e+301, 1.00000000000000000000000000000000000e+00}, + {1.18429898689008480845736170872669145e+301, 1.00000000000000000000000000000000000e+00}, + {1.24069417674199355221183003856003627e+301, 1.00000000000000000000000000000000000e+00}, + {1.29708936659390229596629836839338109e+301, 1.00000000000000000000000000000000000e+00}, + {1.35348455644581103972076669822672591e+301, 1.00000000000000000000000000000000000e+00}, + {1.40987974629771978347523502806007073e+301, 1.00000000000000000000000000000000000e+00}, + {1.46627493614962852722970335789341555e+301, 1.00000000000000000000000000000000000e+00}, + {1.52267012600153727098417168772676037e+301, 1.00000000000000000000000000000000000e+00}, + {1.57906531585344601473864001756010519e+301, 1.00000000000000000000000000000000000e+00}, + {1.63546050570535475849310834739345001e+301, 1.00000000000000000000000000000000000e+00}, + {1.69185569555726350224757667722679483e+301, 1.00000000000000000000000000000000000e+00}, + {1.74825088540917224600204500706013965e+301, 1.00000000000000000000000000000000000e+00}, + {1.80464607526108098975651333689348447e+301, 1.00000000000000000000000000000000000e+00}, + {1.86104126511298973351098166672682928e+301, 1.00000000000000000000000000000000000e+00}, + {1.91743645496489847726544999656017410e+301, 1.00000000000000000000000000000000000e+00}, + {1.97383164481680722101991832639351892e+301, 1.00000000000000000000000000000000000e+00}, + {2.03022683466871596477438665622686374e+301, 1.00000000000000000000000000000000000e+00}, + {2.08662202452062470852885498606020856e+301, 1.00000000000000000000000000000000000e+00}, + {2.14301721437253345228332331589355338e+301, 1.00000000000000000000000000000000000e+00}, + {4.94065645841246544176568792868221372e-324, 4.94065645841246544176568792868221372e-324}, + {4.94065645841246544176568792868221372e-324, 4.94065645841246544176568792868221372e-324}, + {4.99999999999999944488848768742172979e-01, 4.62117157260009714845699443492203290e-01}, + {5.00000000000000000000000000000000000e-01, 4.62117157260009758502318483643672557e-01}, + {5.00000000000000111022302462515654042e-01, 4.62117157260009845815556563946604302e-01}, + {5.49306144334054669009503868437604979e-01, 4.99999999999999867483910937482244858e-01}, + {5.49306144334054780031806330953259021e-01, 4.99999999999999950750637784368995452e-01}, + {5.49306144334054891054108793468913063e-01, 5.00000000000000034017364631255736851e-01}, + {2.19999999999999964472863211994990706e+01, 9.99999999999999999844377355177323009e-01}, + {2.20000000000000000000000000000000000e+01, 9.99999999999999999844377355177324068e-01}, + {2.20000000000000035527136788005009294e+01, 9.99999999999999999844377355177325223e-01}, + {6.93147180559945397249066445510834455e-01, 6.00000000000000056212373967393698031e-01}, + {6.93147180559945286226763982995180413e-01, 5.99999999999999985158100391383682202e-01}, + {6.93147180559945175204461520479526371e-01, 5.99999999999999914103826815373657032e-01}, + {3.46573590279972698624533222755417228e-01, 3.33333333333333372369704144023402903e-01}, + {3.46573590279972643113381991497590207e-01, 3.33333333333333323026458605127557235e-01}, + {3.46573590279972587602230760239763185e-01, 3.33333333333333273683213066231709688e-01}, + {1.73286795139986349312266611377708614e-01, 1.71572875253809923708199182915954510e-01}, + {1.73286795139986321556690995748795103e-01, 1.71572875253809896769671427846052946e-01}, + {1.73286795139986293801115380119881593e-01, 1.71572875253809869831143672776151118e-01}, + {8.66433975699931746561333056888543069e-02, 8.64272337258898029408455765418952337e-02}, + {8.66433975699931607783454978743975516e-02, 8.64272337258897891667202185946638536e-02}, + {8.66433975699931469005576900599407963e-02, 8.64272337258897753925948606474324374e-02}, + {4.33216987849965873280666528444271535e-02, 4.32946174993891841617996586480128793e-02}, + {4.33216987849965803891727489371987758e-02, 4.32946174993891772359121833444914284e-02}, + {4.33216987849965734502788450299703982e-02, 4.32946174993891703100247080409699774e-02}, + {2.16608493924982936640333264222135767e-02, 2.16574623262262954492383391751347008e-02}, + {2.16608493924982901945863744685993879e-02, 2.16574623262262919814187163069359478e-02}, + {2.16608493924982867251394225149851991e-02, 2.16574623262262885135990934387371889e-02}, + {2.16608493924982867251394225149851991e-02, 2.16574623262262885135990934387371889e-02}, + {2.16608493924982901945863744685993879e-02, 2.16574623262262919814187163069359478e-02}, + {2.16608493924982936640333264222135767e-02, 2.16574623262262954492383391751347008e-02}, + {4.33216987849965734502788450299703982e-02, 4.32946174993891703100247080409699774e-02}, + {4.33216987849965803891727489371987758e-02, 4.32946174993891772359121833444914284e-02}, + {4.33216987849965873280666528444271535e-02, 4.32946174993891841617996586480128793e-02}, + {8.66433975699931469005576900599407963e-02, 8.64272337258897753925948606474324374e-02}, + {8.66433975699931607783454978743975516e-02, 8.64272337258897891667202185946638536e-02}, + {8.66433975699931746561333056888543069e-02, 8.64272337258898029408455765418952337e-02}, + {1.73286795139986293801115380119881593e-01, 1.71572875253809869831143672776151118e-01}, + {1.73286795139986321556690995748795103e-01, 1.71572875253809896769671427846052946e-01}, + {1.73286795139986349312266611377708614e-01, 1.71572875253809923708199182915954510e-01}, + {3.46573590279972587602230760239763185e-01, 3.33333333333333273683213066231709688e-01}, + {3.46573590279972643113381991497590207e-01, 3.33333333333333323026458605127557235e-01}, + {3.46573590279972698624533222755417228e-01, 3.33333333333333372369704144023402903e-01}, + {6.93147180559945175204461520479526371e-01, 5.99999999999999914103826815373657032e-01}, + {6.93147180559945286226763982995180413e-01, 5.99999999999999985158100391383682202e-01}, + {6.93147180559945397249066445510834455e-01, 6.00000000000000056212373967393698031e-01}, + {7.09782712893383859409368596971035004e+02, 1.00000000000000000000000000000000000e+00}, + {7.09782712893383973096206318587064743e+02, 1.00000000000000000000000000000000000e+00}, + {7.09782712893384086783044040203094482e+02, 1.00000000000000000000000000000000000e+00}, + {7.41782712893384086783044040203094482e+02, 1.00000000000000000000000000000000000e+00}, + {7.41782712893383973096206318587064743e+02, 1.00000000000000000000000000000000000e+00}, + {7.41782712893383859409368596971035004e+02, 1.00000000000000000000000000000000000e+00}, + {7.10475860073943749739555642008781433e+02, 1.00000000000000000000000000000000000e+00}, + {7.10475860073943863426393363624811172e+02, 1.00000000000000000000000000000000000e+00}, + {7.10475860073943977113231085240840912e+02, 1.00000000000000000000000000000000000e+00}, + {7.09782712893384086783044040203094482e+02, 1.00000000000000000000000000000000000e+00}, + {7.09782712893383973096206318587064743e+02, 1.00000000000000000000000000000000000e+00}, + {7.09782712893383859409368596971035004e+02, 1.00000000000000000000000000000000000e+00}, + {9.22337203685477478400000000000000000e+18, 1.00000000000000000000000000000000000e+00}, + {9.22337203685477580800000000000000000e+18, 1.00000000000000000000000000000000000e+00}, + {9.22337203685477785600000000000000000e+18, 1.00000000000000000000000000000000000e+00}, + {1.34217727999999985098838806152343750e+08, 1.00000000000000000000000000000000000e+00}, + {1.34217728000000000000000000000000000e+08, 1.00000000000000000000000000000000000e+00}, + {1.34217728000000029802322387695312500e+08, 1.00000000000000000000000000000000000e+00}, + {1.67772159999999981373548507690429688e+07, 1.00000000000000000000000000000000000e+00}, + {1.67772160000000000000000000000000000e+07, 1.00000000000000000000000000000000000e+00}, + {1.67772160000000037252902984619140625e+07, 1.00000000000000000000000000000000000e+00}, + {3.19999999999999964472863211994990706e+01, 9.99999999999999999999999999679237812e-01}, + {3.20000000000000000000000000000000000e+01, 9.99999999999999999999999999679237812e-01}, + {3.20000000000000071054273576010018587e+01, 9.99999999999999999999999999679237812e-01}, + {1.59999999999999982236431605997495353e+01, 9.99999999999974671668901811879331665e-01}, + {1.60000000000000000000000000000000000e+01, 9.99999999999974671668901811969315927e-01}, + {1.60000000000000035527136788005009294e+01, 9.99999999999974671668901812149284547e-01}, + {7.99999999999999911182158029987476766e+00, 9.99999774929675889809619027791781323e-01}, + {8.00000000000000000000000000000000000e+00, 9.99999774929675889810018832956368404e-01}, + {8.00000000000000177635683940025046468e+00, 9.99999774929675889810818443285542469e-01}, + {3.99999999999999955591079014993738383e+00, 9.99329299739067043196741615068852355e-01}, + {4.00000000000000000000000000000000000e+00, 9.99329299739067043792243344341724993e-01}, + {4.00000000000000088817841970012523234e+00, 9.99329299739067044983246802887468536e-01}, + {1.99999999999999977795539507496869192e+00, 9.64027580075816868258779231952432911e-01}, + {2.00000000000000000000000000000000000e+00, 9.64027580075816883946413724100923171e-01}, + {2.00000000000000044408920985006261617e+00, 9.64027580075816915321682708397883469e-01}, + {9.99999999999999888977697537484345958e-01, 7.61594155955764841492939901436512668e-01}, + {1.00000000000000000000000000000000000e+00, 7.61594155955764888119458282604793657e-01}, + {1.00000000000000022204460492503130808e+00, 7.61594155955764981372495044941331753e-01}, + {4.99999999999999944488848768742172979e-01, 4.62117157260009714845699443492203290e-01}, + {5.00000000000000000000000000000000000e-01, 4.62117157260009758502318483643672557e-01}, + {5.00000000000000111022302462515654042e-01, 4.62117157260009845815556563946604302e-01}, + {2.49999999999999972244424384371086489e-01, 2.44918662403709103187147915631612892e-01}, + {2.50000000000000000000000000000000000e-01, 2.44918662403709129277801131491016945e-01}, + {2.50000000000000055511151231257827021e-01, 2.44918662403709181459107563209824042e-01}, + {1.24999999999999986122212192185543245e-01, 1.24353001771596194391460985792144305e-01}, + {1.25000000000000000000000000000000000e-01, 1.24353001771596208054647275805892707e-01}, + {1.25000000000000027755575615628913511e-01, 1.24353001771596235381019855833389378e-01}, + {6.24999999999999930611060960927716224e-02, 6.24187467475125075782836114480350829e-02}, + {6.25000000000000000000000000000000000e-02, 6.24187467475125144901428911942113317e-02}, + {6.25000000000000138777878078144567553e-02, 6.24187467475125283138614506865638292e-02}, + {3.12499999999999965305530480463858112e-02, 3.12398314460312533021176543496182149e-02}, + {3.12500000000000000000000000000000000e-02, 3.12398314460312567681786791091369499e-02}, + {3.12500000000000069388939039072283776e-02, 3.12398314460312637003007286281744168e-02}, + {1.56249999999999982652765240231929056e-02, 1.56237285584088634680488027509294906e-02}, + {1.56250000000000000000000000000000000e-02, 1.56237285584088652023488311762919065e-02}, + {1.56250000000000034694469519536141888e-02, 1.56237285584088686709488880270167445e-02}, + {6.10351562499999932237364219655972875e-05, 6.10351561742087681889301535131725312e-05}, + {6.10351562500000000000000000000000000e-05, 6.10351561742087749651937063040263414e-05}, + {6.10351562500000135525271560688054251e-05, 6.10351561742087885177208118857339557e-05}, + {9.31322574615478412227423430871540641e-10, 9.31322574615478411958158908556102005e-10}, + {9.31322574615478515625000000000000000e-10, 9.31322574615478515355735477684561274e-10}, + {9.31322574615478722420153138256918718e-10, 9.31322574615478722150888615941479902e-10}, + {2.77555756156289104291028806826931429e-17, 2.77555756156289104291028806826931349e-17}, + {2.77555756156289135105907917022705078e-17, 2.77555756156289135105907917022704998e-17}, + {2.77555756156289196735666137414252376e-17, 2.77555756156289196735666137414252322e-17}, + {1.79769313486231570814527423731704357e+308, 1.00000000000000000000000000000000000e+00}, + {1.79769313486231570814527423731704357e+308, 1.00000000000000000000000000000000000e+00}, + {1.79769313486231570814527423731704357e+308, 1.00000000000000000000000000000000000e+00}, + {1.79769313486231550856124328384506240e+308, 1.00000000000000000000000000000000000e+00}, + {3.14159265358979311599796346854418516e+00, 9.96272076220749943353314537833579484e-01}, + {1.57079632679489655799898173427209258e+00, 9.17152335667274336647462811870662140e-01}, + {1.00000000000000022204460492503130808e+00, 7.61594155955764981372495044941331753e-01}, + {1.00000000000000000000000000000000000e+00, 7.61594155955764888119458282604793657e-01}, + {9.99999999999999888977697537484345958e-01, 7.61594155955764841492939901436512668e-01}, + {7.85398163397448278999490867136046290e-01, 6.55794202632672418203926030568705821e-01}, + {2.22507385850720187715587855857894824e-308, 2.22507385850720187715587855857894824e-308}, + {2.22507385850720138309023271733240406e-308, 2.22507385850720138309023271733240406e-308}, + {2.22507385850720088902458687608585989e-308, 2.22507385850720088902458687608585989e-308}, + {2.22507385850720039495894103483931571e-308, 2.22507385850720039495894103483931571e-308}, + {9.88131291682493088353137585736442745e-324, 9.88131291682493088353137585736442745e-324}, + {4.94065645841246544176568792868221372e-324, 4.94065645841246544176568792868221372e-324}, + }; + + for (int i = 0; i < testCases.length; i++) { + double[] testCase = testCases[i]; + failures += testTanhCaseWithUlpDiff(testCase[0], + testCase[1], + 3.0); + } + return failures; } diff --git a/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java new file mode 100644 index 0000000000000..60ba4af590e78 --- /dev/null +++ b/test/jdk/java/lang/invoke/TestLambdaFormCustomization.java @@ -0,0 +1,70 @@ +/* + * 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. + */ + +import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; +import java.util.ArrayList; + +/** + * @test + * @bug 8340812 + * @summary Verify that LambdaForm customization via MethodHandle::updateForm is thread safe. + * @run main TestLambdaFormCustomization + * @run main/othervm -Djava.lang.invoke.MethodHandle.CUSTOMIZE_THRESHOLD=0 TestLambdaFormCustomization + */ +public class TestLambdaFormCustomization { + + String str = "test"; + static final String value = "test" + 42; + + // Trigger concurrent LambdaForm customization for VarHandle invokers + void test() throws NoSuchFieldException, IllegalAccessException { + VarHandle varHandle = MethodHandles.lookup().in(getClass()).findVarHandle(getClass(), "str", String.class); + + ArrayList threads = new ArrayList<>(); + for (int threadIdx = 0; threadIdx < 10; threadIdx++) { + threads.add(new Thread(() -> { + for (int i = 0; i < 1000; i++) { + varHandle.compareAndExchange(this, value, value); + varHandle.compareAndExchange(this, value, value); + varHandle.compareAndExchange(this, value, value); + } + })); + } + threads.forEach(Thread::start); + threads.forEach(t -> { + try { + t.join(); + } catch (Throwable e) { + throw new IllegalStateException(e); + } + }); + } + + public static void main(String[] args) throws Exception { + TestLambdaFormCustomization t = new TestLambdaFormCustomization(); + for (int i = 0; i < 4000; ++i) { + t.test(); + } + } +} diff --git a/test/jdk/java/net/InetAddress/ptr/Lookup.java b/test/jdk/java/net/InetAddress/ptr/Lookup.java index 79c53190c24d0..1248916023ec0 100644 --- a/test/jdk/java/net/InetAddress/ptr/Lookup.java +++ b/test/jdk/java/net/InetAddress/ptr/Lookup.java @@ -114,6 +114,9 @@ public static void main(String args[]) throws IOException { // Now check that a reverse lookup will succeed with the dual stack. InetAddress ia = InetAddress.getByName(addr); String name = ia.getHostName(); + // output details of dual stack lookup by address + System.out.println("dual stack lookup for addr " + addr + " returned IP address " + ia); + System.out.println(" with hostname " + name); System.out.println("(default) " + addr + "--> " + name + " (reversed IPv4: " + ipv4Reversed + ")"); diff --git a/test/jdk/java/net/ipv6tests/Tests.java b/test/jdk/java/net/ipv6tests/Tests.java index 398a3e716936c..7a6917a60382f 100644 --- a/test/jdk/java/net/ipv6tests/Tests.java +++ b/test/jdk/java/net/ipv6tests/Tests.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. + * 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 @@ -123,7 +123,8 @@ public static void datagramEcho (DatagramSocket s1, DatagramSocket s2, } dprintln ("dest2 = " + dest2); - + dprintln ("sender endpoint = " + s1.getLocalSocketAddress()); + dprintln ("echo endpoint = " + s2.getLocalSocketAddress()); DatagramPacket r1 = new DatagramPacket (new byte[256], 256); DatagramPacket r2 = new DatagramPacket (new byte[256], 256); diff --git a/test/jdk/java/nio/file/Files/Links.java b/test/jdk/java/nio/file/Files/Links.java index a87647e08a639..23059b0829abb 100644 --- a/test/jdk/java/nio/file/Files/Links.java +++ b/test/jdk/java/nio/file/Files/Links.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2008, 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 @@ -22,7 +22,7 @@ */ /* @test - * @bug 4313887 6838333 6863864 + * @bug 4313887 6838333 6863864 8340329 * @summary Unit test for java.nio.file.Files createSymbolicLink, * readSymbolicLink, and createLink methods * @library .. @@ -45,7 +45,7 @@ static void assertTrue(boolean okay) { } /** - * Exercise createSymbolicLink and readLink methods + * Exercise createSymbolicLink and readSymbolicLink methods */ static void testSymLinks(Path dir) throws IOException { final Path link = dir.resolve("link"); @@ -131,6 +131,27 @@ static void testSymLinks(Path dir) throws IOException { Files.deleteIfExists(mydir); Files.deleteIfExists(link); } + + // Check message of NotLinkException + try { + Files.createDirectory(mydir); + + try { + Path mytarget = Files.readSymbolicLink(mydir); + } catch (NotLinkException expected) { + String filename = mydir.getFileName().toString(); + String message = expected.getMessage(); + boolean okay = message.contains(filename); + if (!okay) { + System.err.println("Message \"" + message + "\"" + + " does not contain the filename \"" + + filename + "\""); + assertTrue(okay); + } + } + } finally { + Files.deleteIfExists(mydir); + } } /** diff --git a/test/jdk/java/security/Security/ConfigFileTest.java b/test/jdk/java/security/Security/ConfigFileTest.java index b9264b937ec74..caf657005e1ba 100644 --- a/test/jdk/java/security/Security/ConfigFileTest.java +++ b/test/jdk/java/security/Security/ConfigFileTest.java @@ -21,155 +21,907 @@ * questions. */ +import com.sun.net.httpserver.HttpExchange; +import com.sun.net.httpserver.HttpServer; import jdk.test.lib.Utils; import jdk.test.lib.process.OutputAnalyzer; import jdk.test.lib.process.ProcessTools; +import jdk.test.lib.util.FileUtils; +import sun.net.www.ParseUtil; +import java.io.Closeable; import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; import java.io.UncheckedIOException; -import java.nio.file.*; - -import java.security.Provider; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.CharBuffer; +import java.nio.file.Files; +import java.nio.file.InvalidPathException; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; import java.security.Security; +import java.time.Instant; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collections; -import java.util.Optional; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Stream; /* * @test - * @summary Throw error if default java.security file is missing - * @bug 8155246 8292297 8292177 8281658 + * @summary Tests security properties passed through java.security, + * java.security.properties or included from other properties files. + * @bug 8155246 8292297 8292177 8281658 8319332 + * @modules java.base/sun.net.www * @library /test/lib * @run main ConfigFileTest */ + public class ConfigFileTest { + static final String SEPARATOR_THIN = "----------------------------"; + + private static void printTestHeader(String testName) { + System.out.println(); + System.out.println(SEPARATOR_THIN); + System.out.println(testName); + System.out.println(SEPARATOR_THIN); + System.out.println(); + } + + public static void main(String[] args) throws Exception { + if (args.length == 1 && Executor.RUNNER_ARG.equals(args[0])) { + // Executed by a test-launched JVM. + // Force the initialization of java.security.Security. + Security.getProviders(); + Security.setProperty("postInitTest", "shouldNotRecord"); + System.out.println(FilesManager.LAST_FILE_PROP_NAME + ": " + + Security.getProperty(FilesManager.LAST_FILE_PROP_NAME)); + assertTestSecuritySetPropertyShouldNotInclude(); + } else { + // Executed by the test JVM. + try (FilesManager filesMgr = new FilesManager()) { + for (Method m : ConfigFileTest.class.getDeclaredMethods()) { + if (m.getName().startsWith("test")) { + printTestHeader(m.getName()); + Executor.run(m, filesMgr); + } + } + } + } + } + + /* + * Success cases + */ + + static void testShowSettings(Executor ex, FilesManager filesMgr) + throws Exception { + // Sanity test passing the -XshowSettings:security option. + ex.addJvmArg("-XshowSettings:security"); + ex.setMasterFile(filesMgr.newMasterFile()); + ex.assertSuccess(); + ex.getOutputAnalyzer() + .shouldContain("Security properties:") + .shouldContain("Security provider static configuration:") + .shouldContain("Security TLS configuration"); + } - private static final String EXPECTED_DEBUG_OUTPUT = - "Initial security property: crypto.policy=unlimited"; + static void testIncludeBasic(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + PropsFile file2 = filesMgr.newFile("dir1/dir2/file2.properties"); - private static final String UNEXPECTED_DEBUG_OUTPUT = - "Initial security property: postInitTest=shouldNotRecord"; + masterFile.addAbsoluteInclude(file0); + extraFile.addRelativeInclude(file2); + file2.addAbsoluteInclude(file1); - private static boolean overrideDetected = false; + ex.setMasterFile(masterFile); + ex.setExtraFile(extraFile, Executor.ExtraMode.FILE_URI, false); + ex.assertSuccess(); + } - private static Path COPY_JDK_DIR = Path.of("./jdk-8155246-tmpdir"); - private static Path COPIED_JAVA = COPY_JDK_DIR.resolve("bin", "java"); + static void testRepeatedInclude(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); - public static void main(String[] args) throws Exception { - Path copyJdkDir = Path.of("./jdk-8155246-tmpdir"); - Path copiedJava = Optional.of( - Path.of(copyJdkDir.toString(), "bin", "java")) - .orElseThrow(() -> new RuntimeException("Unable to locate new JDK") - ); - - if (args.length == 1) { - // set up is complete. Run code to exercise loading of java.security - Provider[] provs = Security.getProviders(); - Security.setProperty("postInitTest", "shouldNotRecord"); - System.out.println(Arrays.toString(provs) + "NumProviders: " + provs.length); + masterFile.addAbsoluteInclude(file0); + masterFile.addAbsoluteInclude(file1); + masterFile.addAbsoluteInclude(file0); + file1.addRelativeInclude(file0); + + ex.setMasterFile(masterFile); + ex.assertSuccess(); + } + + static void testIncludeWithOverrideAll(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + + masterFile.addRelativeInclude(file0); + extraFile.addAbsoluteInclude(file1); + + ex.setMasterFile(masterFile); + ex.setExtraFile(extraFile, Executor.ExtraMode.HTTP_SERVED, true); + ex.assertSuccess(); + } + + static void extraPropertiesByHelper(Executor ex, FilesManager filesMgr, + Executor.ExtraMode mode) throws Exception { + ExtraPropsFile extraFile = filesMgr.newExtraFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + extraFile.addRelativeInclude(file0); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, mode, true); + ex.assertSuccess(); + } + + static void testExtraPropertiesByPathAbsolute(Executor ex, + FilesManager filesMgr) throws Exception { + extraPropertiesByHelper(ex, filesMgr, Executor.ExtraMode.PATH_ABS); + } + + static void testExtraPropertiesByPathRelative(Executor ex, + FilesManager filesMgr) throws Exception { + extraPropertiesByHelper(ex, filesMgr, Executor.ExtraMode.PATH_REL); + } + + static void specialCharsIncludes(Executor ex, FilesManager filesMgr, + char specialChar, Executor.ExtraMode extraMode, + boolean useRelativeIncludes) throws Exception { + String suffix = specialChar + ".properties"; + ExtraPropsFile extraFile; + PropsFile file0, file1; + try { + extraFile = filesMgr.newExtraFile("extra" + suffix); + file0 = filesMgr.newFile("file0" + suffix); + file1 = filesMgr.newFile("file1" + suffix); + } catch (InvalidPathException ipe) { + // The platform encoding may not allow to create files with some + // special characters. Skip the test in these cases. + return; + } + + if (useRelativeIncludes) { + extraFile.addRelativeInclude(file0); } else { - Files.createDirectory(copyJdkDir); - Path jdkTestDir = Path.of(Optional.of(System.getProperty("test.jdk")) - .orElseThrow(() -> new RuntimeException("Couldn't load JDK Test Dir")) - ); - - copyJDK(jdkTestDir, copyJdkDir); - String extraPropsFile = Path.of(System.getProperty("test.src"), "override.props").toString(); - - // sanity test -XshowSettings:security option - exerciseShowSettingsSecurity(buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-XshowSettings:security", "ConfigFileTest", "runner")); - - // exercise some debug flags while we're here - // regular JDK install - should expect success - exerciseSecurity(0, "java", - buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-Djavax.net.debug=all", "ConfigFileTest", "runner")); - - // given an overriding security conf file that doesn't exist, we shouldn't - // overwrite the properties from original/master security conf file - exerciseSecurity(0, "SUN version", - buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-Djavax.net.debug=all", - "-Djava.security.properties==file:///" + extraPropsFile + "badFileName", - "ConfigFileTest", "runner")); - - // test JDK launch with customized properties file - exerciseSecurity(0, "NumProviders: 6", - buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-Djavax.net.debug=all", - "-Djava.security.properties==file:///" + extraPropsFile, - "ConfigFileTest", "runner")); - - // delete the master conf file - Files.delete(Path.of(copyJdkDir.toString(), "conf", - "security","java.security")); - - // launch JDK without java.security file being present or specified - exerciseSecurity(1, "Error loading java.security file", - buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-Djavax.net.debug=all", - "ConfigFileTest", "runner")); - - // test the override functionality also. Should not be allowed since - // "security.overridePropertiesFile=true" Security property is missing. - exerciseSecurity(1, "Error loading java.security file", - buildCommand("-cp", System.getProperty("test.classes"), - "-Djava.security.debug=all", "-Djavax.net.debug=all", - "-Djava.security.properties==file:///" + extraPropsFile, "ConfigFileTest", "runner")); - - if (!overrideDetected) { - throw new RuntimeException("Override scenario not seen"); + extraFile.addAbsoluteInclude(file0); + } + extraFile.addAbsoluteInclude(file1); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, extraMode, false); + ex.assertSuccess(); + } + + static void testUnicodeIncludes1(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, '\u2022', + Executor.ExtraMode.PATH_ABS, true); + } + + static void testUnicodeIncludes2(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, '\u2022', + Executor.ExtraMode.FILE_URI, true); + } + + static void testUnicodeIncludes3(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:/tmp/extra•.properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, '\u2022', + Executor.ExtraMode.RAW_FILE_URI1, false); + } + + static void testUnicodeIncludes4(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:///tmp/extra•.properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, '\u2022', + Executor.ExtraMode.RAW_FILE_URI2, false); + } + + static void testSpaceIncludes1(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, ' ', + Executor.ExtraMode.PATH_ABS, true); + } + + static void testSpaceIncludes2(Executor ex, FilesManager filesMgr) + throws Exception { + specialCharsIncludes(ex, filesMgr, ' ', + Executor.ExtraMode.FILE_URI, true); + } + + static void testSpaceIncludes3(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:/tmp/extra .properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, ' ', + Executor.ExtraMode.RAW_FILE_URI1, false); + } + + static void testSpaceIncludes4(Executor ex, FilesManager filesMgr) + throws Exception { + // Backward compatibility check. Malformed URLs such as + // file:///tmp/extra .properties are supported for the extra file. + // However, relative includes are not allowed in these cases. + specialCharsIncludes(ex, filesMgr, ' ', + Executor.ExtraMode.RAW_FILE_URI2, false); + } + + static void notOverrideOnFailureHelper(Executor ex, FilesManager filesMgr, + String nonExistentExtraFile) throws Exception { + // An overriding extra properties file that does not exist + // should not erase properties from the master file. + ex.setIgnoredExtraFile(nonExistentExtraFile, true); + ex.setMasterFile(filesMgr.newMasterFile()); + ex.assertSuccess(); + ex.getOutputAnalyzer().shouldContain("unable to load security " + + "properties from " + nonExistentExtraFile); + } + + static void testNotOverrideOnEmptyFailure(Executor ex, + FilesManager filesMgr) throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, ""); + ex.getOutputAnalyzer() + .shouldContain("Empty extra properties file path"); + } + + static void testNotOverrideOnURLFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, + "file:///nonExistentFile.properties"); + } + + static void testNotOverrideOnPathFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "nonExistentFile.properties"); + } + + static void testNotOverrideOnDirFailure(Executor ex, FilesManager filesMgr) + throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "file:///"); + ex.getOutputAnalyzer().shouldContain("Is a directory"); + } + + static void testNotOverrideOnBadFileURLFailure(Executor ex, + FilesManager filesMgr) throws Exception { + notOverrideOnFailureHelper(ex, filesMgr, "file:///%00"); + } + + static void testDisabledExtraPropertiesFile(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + masterFile.addRawProperty("security.overridePropertiesFile", "false"); + + ex.setMasterFile(masterFile); + ex.setIgnoredExtraFile(file0.path.toString(), true); + ex.assertSuccess(); + } + + static final String SECURITY_SET_PROP_FILE_PATH = + "testSecuritySetPropertyShouldNotInclude.propsFilePath"; + + static void testSecuritySetPropertyShouldNotInclude(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + ex.addSystemProp(SECURITY_SET_PROP_FILE_PATH, file0.path.toString()); + ex.setMasterFile(masterFile); + ex.assertSuccess(); + } + + static void assertTestSecuritySetPropertyShouldNotInclude() { + // This check is executed by the launched JVM. + String propsFilePath = System.getProperty(SECURITY_SET_PROP_FILE_PATH); + if (propsFilePath != null) { + String name = Path.of(propsFilePath).getFileName().toString(); + String setPropInvokeRepr = "Security.setProperty(\"include\", " + + "\"" + propsFilePath + "\")"; + try { + Security.setProperty("include", propsFilePath); + throw new RuntimeException(setPropInvokeRepr + " was " + + "expected to throw IllegalArgumentException."); + } catch (IllegalArgumentException expected) {} + if (FilesManager.APPLIED_PROP_VALUE.equals( + Security.getProperty(name))) { + throw new RuntimeException(setPropInvokeRepr + " caused " + + "a file inclusion."); } + try { + Security.getProperty("include"); + throw new RuntimeException("Security.getProperty(\"include\")" + + " was expected to throw IllegalArgumentException."); + } catch (IllegalArgumentException expected) {} } } - private static ProcessBuilder buildCommand(String... command) { - ArrayList args = new ArrayList<>(); - args.add(COPIED_JAVA.toString()); - Collections.addAll(args, Utils.prependTestJavaOpts(command)); - return new ProcessBuilder(args); + /* + * Error cases + */ + + static void testCannotResolveRelativeFromHTTPServed(Executor ex, + FilesManager filesMgr) throws Exception { + ExtraPropsFile extraFile = filesMgr.newExtraFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + + extraFile.addRelativeInclude(file0); + + ex.setMasterFile(filesMgr.newMasterFile()); + ex.setExtraFile(extraFile, Executor.ExtraMode.HTTP_SERVED, true); + ex.assertError("InternalError: Cannot resolve '" + file0.fileName + + "' relative path when included from a non-regular " + + "properties file (e.g. HTTP served file)"); } - private static void exerciseSecurity(int exitCode, String output, ProcessBuilder process) throws Exception { - OutputAnalyzer oa = ProcessTools.executeProcess(process); - oa.shouldHaveExitValue(exitCode) - .shouldContain(output); + static void testCannotIncludeCycles(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + PropsFile file0 = filesMgr.newFile("file0.properties"); + PropsFile file1 = filesMgr.newFile("dir1/file1.properties"); + + // Includes chain: master -> file0 -> file1 -> master. + file1.addRelativeInclude(masterFile); + file0.addRelativeInclude(file1); + masterFile.addRelativeInclude(file0); - // extra checks on debug output - if (exitCode != 1) { - if (oa.getStderr().contains("overriding other security properties files!")) { - overrideDetected = true; - // master file is not in use - only provider properties are set in custom file - oa.shouldContain("security.provider.2=SunRsaSign") - .shouldNotContain(EXPECTED_DEBUG_OUTPUT) - .shouldNotContain(UNEXPECTED_DEBUG_OUTPUT); + ex.setMasterFile(masterFile); + ex.assertError( + "InternalError: Cyclic include of '" + masterFile.path + "'"); + } + + static void testCannotIncludeURL(Executor ex, FilesManager filesMgr) + throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + ExtraPropsFile extraFile = filesMgr.newExtraFile(); + + masterFile.addRawProperty("include", extraFile.url.toString()); + + ex.setMasterFile(masterFile); + ex.assertError("InternalError: Unable to include 'http://127.0.0.1:"); + } + + static void testCannotIncludeNonexistentFile(Executor ex, + FilesManager filesMgr) throws Exception { + PropsFile masterFile = filesMgr.newMasterFile(); + + String nonexistentPath = "/nonExistentFile.properties"; + masterFile.addRawProperty("include", nonexistentPath); + + ex.setMasterFile(masterFile); + ex.assertError( + "InternalError: Unable to include '" + nonexistentPath + "'"); + } + + static void testMustHaveMasterFile(Executor ex, FilesManager filesMgr) + throws Exception { + // Launch a JDK without a master java.security file present. + ex.assertError("InternalError: Error loading java.security file"); + } + + static void testMustHaveMasterFileEvenWithExtraFile(Executor ex, + FilesManager filesMgr) throws Exception { + // Launch a JDK without a master java.security file present, but with an + // extra file passed. Since the "security.overridePropertiesFile=true" + // security property is missing, it should fail anyway. + ex.setExtraFile( + filesMgr.newExtraFile(), Executor.ExtraMode.FILE_URI, true); + ex.assertError("InternalError: Error loading java.security file"); + } +} + +sealed class PropsFile permits ExtraPropsFile { + protected static final class Include { + final PropsFile propsFile; + final String value; + + private Include(PropsFile propsFile, String value) { + this.propsFile = propsFile; + this.value = value; + } + + static Include of(PropsFile propsFile) { + return new Include(propsFile, propsFile.path.toString()); + } + + static Include of(PropsFile propsFile, String value) { + return new Include(propsFile, value); + } + } + + protected final List includes = new ArrayList<>(); + protected final PrintWriter writer; + protected boolean includedFromExtra = false; + final String fileName; + final Path path; + + PropsFile(String fileName, Path path) throws IOException { + this.fileName = fileName; + this.path = path; + this.writer = new PrintWriter(Files.newOutputStream(path, + StandardOpenOption.CREATE, StandardOpenOption.APPEND), true); + } + + private static String escape(String text, boolean escapeSpace) { + StringBuilder sb = new StringBuilder(text.length()); + CharBuffer cb = CharBuffer.wrap(text); + while (cb.hasRemaining()) { + char c = cb.get(); + if (c == '\\' || escapeSpace && c == ' ') { + sb.append('\\'); + } + if (Character.UnicodeBlock.of(c) == + Character.UnicodeBlock.BASIC_LATIN) { + sb.append(c); } else { - oa.shouldContain(EXPECTED_DEBUG_OUTPUT) - .shouldNotContain(UNEXPECTED_DEBUG_OUTPUT); + sb.append("\\u%04x".formatted((int) c)); } } + return sb.toString(); } - // exercise the -XshowSettings:security launcher - private static void exerciseShowSettingsSecurity(ProcessBuilder process) throws Exception { - OutputAnalyzer oa = ProcessTools.executeProcess(process); - oa.shouldHaveExitValue(0) - .shouldContain("Security properties:") - .shouldContain("Security provider static configuration:") - .shouldContain("Security TLS configuration"); + private void addRawProperty(String key, String value, String sep) { + writer.println(escape(key, true) + sep + escape(value, false)); + } + + protected void addIncludeDefinition(Include include) { + if (include.propsFile instanceof ExtraPropsFile) { + throw new RuntimeException("ExtraPropsFile should not be included"); + } + includes.add(include); + addRawProperty("include", include.value, " "); + } + + void addComment(String comment) { + writer.println("# " + comment); + } + + void addRawProperty(String key, String value) { + addRawProperty(key, value, "="); + } + + void addAbsoluteInclude(PropsFile propsFile) { + addIncludeDefinition(Include.of(propsFile)); + } + + void addRelativeInclude(PropsFile propsFile) { + addIncludeDefinition(Include.of(propsFile, + path.getParent().relativize(propsFile.path).toString())); + } + + void assertApplied(OutputAnalyzer oa) { + oa.shouldContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + + FilesManager.APPLIED_PROP_VALUE); + for (Include include : includes) { + include.propsFile.assertApplied(oa); + oa.shouldContain("processing include: '" + include.value + "'"); + oa.shouldContain("finished processing " + include.propsFile.path); + } + } + + void assertWasOverwritten(OutputAnalyzer oa) { + oa.shouldNotContain(Executor.INITIAL_PROP_LOG_MSG + fileName + "=" + + FilesManager.APPLIED_PROP_VALUE); + for (Include include : includes) { + if (!include.propsFile.includedFromExtra) { + include.propsFile.assertWasOverwritten(oa); + } + oa.shouldContain("processing include: '" + include.value + "'"); + oa.shouldContain("finished processing " + include.propsFile.path); + } + } + + void markAsIncludedFromExtra() { + includedFromExtra = true; + for (Include include : includes) { + include.propsFile.markAsIncludedFromExtra(); + } + } + + PropsFile getLastFile() { + return includes.isEmpty() ? + this : includes.getLast().propsFile.getLastFile(); } - private static void copyJDK(Path src, Path dst) throws Exception { - Files.walk(src) - .skip(1) - .forEach(file -> { + void close() { + writer.close(); + } +} + +final class ExtraPropsFile extends PropsFile { + private final Map systemProps = new LinkedHashMap<>(); + final URI url; + + ExtraPropsFile(String fileName, URI url, Path path) throws IOException { + super(fileName, path); + this.url = url; + } + + @Override + protected void addIncludeDefinition(Include include) { + if (includes.isEmpty()) { + String propName = "props.fileName"; + systemProps.put(propName, include.propsFile.fileName); + include = Include.of(include.propsFile, + include.value.replace(include.propsFile.fileName, + "${props.none}${" + propName + "}")); + } + include.propsFile.markAsIncludedFromExtra(); + super.addIncludeDefinition(include); + } + + Map getSystemProperties() { + return Collections.unmodifiableMap(systemProps); + } +} + +final class FilesManager implements Closeable { + private static final Path ROOT_DIR = + Path.of(ConfigFileTest.class.getSimpleName()).toAbsolutePath(); + private static final Path PROPS_DIR = ROOT_DIR.resolve("properties"); + private static final Path JDK_DIR = ROOT_DIR.resolve("jdk"); + private static final Path MASTER_FILE = + JDK_DIR.resolve("conf/security/java.security"); + private static final Path MASTER_FILE_TEMPLATE = + MASTER_FILE.resolveSibling("java.security.template"); + static final String JAVA_EXECUTABLE = + JDK_DIR.resolve("bin/java").toString(); + static final String LAST_FILE_PROP_NAME = "last-file"; + static final String APPLIED_PROP_VALUE = "applied"; + + private final List createdFiles; + private final Set fileNamesInUse; + private final HttpServer httpServer; + private final URI serverUri; + private final long masterFileLines; + + FilesManager() throws Exception { + createdFiles = new ArrayList<>(); + fileNamesInUse = new HashSet<>(); + httpServer = HttpServer.create( + new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 0); + httpServer.createContext("/", this::handleRequest); + InetSocketAddress address = httpServer.getAddress(); + httpServer.start(); + serverUri = new URI("http", null, address.getHostString(), + address.getPort(), null, null, null); + copyJDK(); + try (Stream s = Files.lines(MASTER_FILE_TEMPLATE)) { + masterFileLines = s.count(); + } + } + + private static void copyJDK() throws Exception { + Path testJDK = Path.of(Objects.requireNonNull( + System.getProperty("test.jdk"), "unspecified test.jdk")); + if (!Files.exists(testJDK)) { + throw new RuntimeException("test.jdk -> nonexistent JDK"); + } + Files.createDirectories(JDK_DIR); + try (Stream pathStream = Files.walk(testJDK)) { + pathStream.skip(1).forEach((Path file) -> { try { - Files.copy(file, dst.resolve(src.relativize(file)), StandardCopyOption.COPY_ATTRIBUTES); + Files.copy(file, JDK_DIR.resolve(testJDK.relativize(file)), + StandardCopyOption.COPY_ATTRIBUTES); } catch (IOException ioe) { throw new UncheckedIOException(ioe); } }); + } + Files.move(MASTER_FILE, MASTER_FILE_TEMPLATE); + } + + private void handleRequest(HttpExchange x) throws IOException { + String rawPath = x.getRequestURI().getRawPath(); + Path f = ROOT_DIR.resolve(x.getRequestURI().getPath().substring(1)); + int statusCode; + byte[] responseBody; + // Check for unescaped space, unresolved parent or backward slash. + if (rawPath.matches("^.*( |(\\.|%2[Ee]){2}|\\\\|%5[Cc]).*$")) { + statusCode = HttpURLConnection.HTTP_BAD_REQUEST; + responseBody = new byte[0]; + } else if (Files.isRegularFile(f)) { + x.getResponseHeaders().add("Content-type", "text/plain"); + statusCode = HttpURLConnection.HTTP_OK; + responseBody = Files.readAllBytes(f); + } else { + statusCode = HttpURLConnection.HTTP_NOT_FOUND; + responseBody = new byte[0]; + } + System.out.println("[" + Instant.now() + "] " + + getClass().getSimpleName() + ": " + + x.getRequestMethod() + " " + rawPath + " -> " + + statusCode + " (" + responseBody.length + " bytes)"); + try (OutputStream responseStream = x.getResponseBody()) { + x.sendResponseHeaders(statusCode, responseBody.length); + responseStream.write(responseBody); + } + } + + @FunctionalInterface + private interface PropsFileBuilder { + PropsFile build(String fileName, Path path) throws IOException; + } + + private PropsFile newFile(Path path, PropsFileBuilder builder) + throws IOException { + String fileName = path.getFileName().toString(); + if (!fileNamesInUse.add(fileName)) { + // Names must be unique in order for the special + // property = to work. + throw new RuntimeException(fileName + " is repeated"); + } + Files.createDirectories(path.getParent()); + PropsFile propsFile = builder.build(fileName, path); + propsFile.addComment("Property to determine if this properties file " + + "was parsed and not overwritten:"); + propsFile.addRawProperty(fileName, APPLIED_PROP_VALUE); + propsFile.addComment(ConfigFileTest.SEPARATOR_THIN); + propsFile.addComment("Property to be overwritten by every properties " + + "file (master, extra or included):"); + propsFile.addRawProperty(LAST_FILE_PROP_NAME, fileName); + propsFile.addComment(ConfigFileTest.SEPARATOR_THIN); + createdFiles.add(propsFile); + return propsFile; + } + + PropsFile newFile(String relPathStr) throws IOException { + return newFile(PROPS_DIR.resolve(relPathStr), PropsFile::new); + } + + PropsFile newMasterFile() throws IOException { + Files.copy(MASTER_FILE_TEMPLATE, MASTER_FILE); + return newFile(MASTER_FILE, PropsFile::new); + } + + ExtraPropsFile newExtraFile() throws IOException { + return newExtraFile("extra.properties"); + } + + ExtraPropsFile newExtraFile(String extraFileName) throws IOException { + return (ExtraPropsFile) newFile(PROPS_DIR.resolve(extraFileName), + (fileName, path) -> { + URI uri = serverUri.resolve(ParseUtil.encodePath( + ROOT_DIR.relativize(path).toString())); + return new ExtraPropsFile(fileName, uri, path); + }); + } + + void reportCreatedFiles() throws IOException { + for (PropsFile propsFile : createdFiles) { + System.err.println(); + System.err.println(propsFile.path.toString()); + System.err.println(ConfigFileTest.SEPARATOR_THIN.repeat(3)); + try (Stream lines = Files.lines(propsFile.path)) { + long lineNumber = 1L; + Iterator it = lines.iterator(); + while (it.hasNext()) { + String line = it.next(); + if (!propsFile.path.equals(MASTER_FILE) || + lineNumber > masterFileLines) { + System.err.println(line); + } + lineNumber++; + } + } + System.err.println(); + } + } + + void clear() throws IOException { + if (!createdFiles.isEmpty()) { + for (PropsFile propsFile : createdFiles) { + propsFile.close(); + Files.delete(propsFile.path); + } + FileUtils.deleteFileTreeUnchecked(PROPS_DIR); + createdFiles.clear(); + fileNamesInUse.clear(); + } + } + + @Override + public void close() throws IOException { + clear(); + httpServer.stop(0); + FileUtils.deleteFileTreeUnchecked(ROOT_DIR); + } +} + +final class Executor { + enum ExtraMode { + HTTP_SERVED, FILE_URI, RAW_FILE_URI1, RAW_FILE_URI2, PATH_ABS, PATH_REL + } + static final String RUNNER_ARG = "runner"; + static final String INITIAL_PROP_LOG_MSG = "Initial security property: "; + private static final String OVERRIDING_LOG_MSG = + "overriding other security properties files!"; + private static final String[] ALWAYS_UNEXPECTED_LOG_MSGS = { + "java.lang.AssertionError", + INITIAL_PROP_LOG_MSG + "postInitTest=shouldNotRecord", + INITIAL_PROP_LOG_MSG + "include=", + }; + private static final Path CWD = Path.of(".").toAbsolutePath(); + private static final String JAVA_SEC_PROPS = "java.security.properties"; + private static final String CLASS_PATH = Objects.requireNonNull( + System.getProperty("test.classes"), "unspecified test.classes"); + private static final String DEBUG_ARG = + "-Xrunjdwp:transport=dt_socket,address=localhost:8000,suspend=y"; + private final Map systemProps = new LinkedHashMap<>( + Map.of("java.security.debug", "all", "javax.net.debug", "all", + // Ensure we get UTF-8 debug outputs in Windows: + "stderr.encoding", "UTF-8", "stdout.encoding", "UTF-8")); + private final List jvmArgs = new ArrayList<>( + List.of(FilesManager.JAVA_EXECUTABLE, "-enablesystemassertions", + // Uncomment DEBUG_ARG to debug test-launched JVMs: + "-classpath", CLASS_PATH//, DEBUG_ARG + )); + private PropsFile masterPropsFile; + private ExtraPropsFile extraPropsFile; + private boolean expectedOverrideAll = false; + private OutputAnalyzer oa; + + static void run(Method m, FilesManager filesMgr) throws Exception { + try { + m.invoke(null, new Executor(), filesMgr); + } catch (Throwable e) { + filesMgr.reportCreatedFiles(); + throw e; + } finally { + filesMgr.clear(); + } + } + + void addSystemProp(String key, String value) { + systemProps.put(key, value); + } + + private void setRawExtraFile(String extraFile, boolean overrideAll) { + addSystemProp(JAVA_SEC_PROPS, (overrideAll ? "=" : "") + extraFile); + } + + void setMasterFile(PropsFile masterPropsFile) { + this.masterPropsFile = masterPropsFile; + } + + void setExtraFile(ExtraPropsFile extraPropsFile, ExtraMode mode, + boolean overrideAll) { + this.extraPropsFile = extraPropsFile; + expectedOverrideAll = overrideAll; + setRawExtraFile(switch (mode) { + case HTTP_SERVED -> extraPropsFile.url.toString(); + case FILE_URI -> extraPropsFile.path.toUri().toString(); + case RAW_FILE_URI1 -> "file:" + extraPropsFile.path; + case RAW_FILE_URI2 -> "file://" + + (extraPropsFile.path.startsWith("/") ? "" : "/") + + extraPropsFile.path; + case PATH_ABS -> extraPropsFile.path.toString(); + case PATH_REL -> CWD.relativize(extraPropsFile.path).toString(); + }, overrideAll); + } + + void setIgnoredExtraFile(String extraPropsFile, boolean overrideAll) { + setRawExtraFile(extraPropsFile, overrideAll); + expectedOverrideAll = false; + } + + void addJvmArg(String arg) { + jvmArgs.add(arg); + } + + private void execute(boolean successExpected) throws Exception { + List command = new ArrayList<>(jvmArgs); + Collections.addAll(command, Utils.getTestJavaOpts()); + addSystemPropertiesAsJvmArgs(command); + command.add(ConfigFileTest.class.getSimpleName()); + command.add(RUNNER_ARG); + oa = ProcessTools.executeProcess(new ProcessBuilder(command)); + oa.shouldHaveExitValue(successExpected ? 0 : 1); + for (String output : ALWAYS_UNEXPECTED_LOG_MSGS) { + oa.shouldNotContain(output); + } + } + + private void addSystemPropertiesAsJvmArgs(List command) { + Map allSystemProps = new LinkedHashMap<>(systemProps); + if (extraPropsFile != null) { + allSystemProps.putAll(extraPropsFile.getSystemProperties()); + } + for (Map.Entry e : allSystemProps.entrySet()) { + command.add("-D" + e.getKey() + "=" + e.getValue()); + } + } + + void assertSuccess() throws Exception { + execute(true); + + // Ensure every file was processed by checking a unique property used as + // a flag. Each file defines =applied. + // + // For example: + // + // file0 + // --------------- + // file0=applied + // include file1 + // + // file1 + // --------------- + // file1=applied + // + // The assertion would be file0 == applied AND file1 == applied. + // + if (extraPropsFile != null) { + extraPropsFile.assertApplied(oa); + } + if (expectedOverrideAll) { + // When overriding with an extra file, check that neither + // the master file nor its includes are visible. + oa.shouldContain(OVERRIDING_LOG_MSG); + masterPropsFile.assertWasOverwritten(oa); + } else { + oa.shouldNotContain(OVERRIDING_LOG_MSG); + masterPropsFile.assertApplied(oa); + } + + // Ensure the last included file overwrote a fixed property. Each file + // defines last-file=. + // + // For example: + // + // file0 + // --------------- + // last-file=file0 + // include file1 + // + // file1 + // --------------- + // last-file=file1 + // + // The assertion would be last-file == file1. + // + PropsFile lastFile = (extraPropsFile == null ? + masterPropsFile : extraPropsFile).getLastFile(); + oa.shouldContain(FilesManager.LAST_FILE_PROP_NAME + "=" + + lastFile.fileName); + oa.stdoutShouldContain(FilesManager.LAST_FILE_PROP_NAME + ": " + + lastFile.fileName); + } + + void assertError(String message) throws Exception { + execute(false); + oa.shouldContain(message); + } + + OutputAnalyzer getOutputAnalyzer() { + return oa; } } diff --git a/test/jdk/java/security/Security/override.props b/test/jdk/java/security/Security/override.props deleted file mode 100644 index d0190f576fd82..0000000000000 --- a/test/jdk/java/security/Security/override.props +++ /dev/null @@ -1,7 +0,0 @@ -# exercise ServiceLoader and legacy (class load) approach -security.provider.1=sun.security.provider.Sun -security.provider.2=SunRsaSign -security.provider.3=sun.security.ssl.SunJSSE -security.provider.4=com.sun.crypto.provider.SunJCE -security.provider.5=SunJGSS -security.provider.6=SunSASL \ No newline at end of file diff --git a/test/jdk/java/security/Security/signedfirst/DynStatic.java b/test/jdk/java/security/Security/signedfirst/DynStatic.java index 59e30de54623f..17fab4cac5bfa 100644 --- a/test/jdk/java/security/Security/signedfirst/DynStatic.java +++ b/test/jdk/java/security/Security/signedfirst/DynStatic.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 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 @@ -33,7 +33,6 @@ import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.List; import jdk.test.lib.compiler.CompilerUtils; import jdk.test.lib.process.ProcessTools; @@ -52,9 +51,8 @@ public class DynStatic { Paths.get(TEST_SRC, "DynSignedProvFirst.java"); private static final Path STATIC_SRC = Paths.get(TEST_SRC, "StaticSignedProvFirst.java"); - - private static final String STATIC_PROPS = - Paths.get(TEST_SRC, "Static.props").toString(); + private static final Path STATIC_PROPS = + Paths.get(TEST_SRC, "Static.props"); public static void main(String[] args) throws Exception { @@ -89,7 +87,7 @@ public static void main(String[] args) throws Exception { // Run the StaticSignedProvFirst test program ProcessTools.executeTestJava("-classpath", TEST_CLASSES.toString() + File.pathSeparator + "exp.jar", - "-Djava.security.properties=file:" + STATIC_PROPS, + "-Djava.security.properties=" + STATIC_PROPS.toUri(), "StaticSignedProvFirst") .shouldContain("test passed"); } diff --git a/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java b/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java index 4336377e0c898..3a5430d0573e8 100644 --- a/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java +++ b/test/jdk/java/util/zip/ZipFile/CenSizeTooLarge.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 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 @@ -34,9 +34,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; -import java.nio.charset.StandardCharsets; import java.time.LocalDateTime; -import java.util.Arrays; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; @@ -46,6 +44,10 @@ import static org.junit.jupiter.api.Assertions.assertThrows; public class CenSizeTooLarge { + + // Entry names produced in this test are fixed-length + public static final int NAME_LENGTH = 10; + // Maximum allowed CEN size allowed by the ZipFile implementation static final int MAX_CEN_SIZE = Integer.MAX_VALUE - ZipFile.ENDHDR - 1; @@ -59,11 +61,10 @@ public class CenSizeTooLarge { * fields respectively. The combined length of any * directory record and these three fields SHOULD NOT * generally exceed 65,535 bytes. - * - * Since ZipOutputStream does not enforce the 'combined length' clause, - * we simply use 65,535 (0xFFFF) for the purpose of this test. + *. + * Create a maximum extra field which does not exceed 65,535 bytes */ - static final int MAX_EXTRA_FIELD_SIZE = 65_535; + static final int MAX_EXTRA_FIELD_SIZE = 65_535 - ZipFile.CENHDR - NAME_LENGTH; // Data size (unsigned short) // Field size minus the leading header 'tag' and 'data size' fields (2 bytes each) @@ -72,9 +73,6 @@ public class CenSizeTooLarge { // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' static final short UNKNOWN_ZIP_TAG = (short) 0x9902; - // Entry names produced in this test are fixed-length - public static final int NAME_LENGTH = 10; - // Use a shared LocalDateTime on all entries to save processing time static final LocalDateTime TIME_LOCAL = LocalDateTime.now(); @@ -84,16 +82,16 @@ public class CenSizeTooLarge { // The number of entries needed to exceed the MAX_CEN_SIZE static final int NUM_ENTRIES = (MAX_CEN_SIZE / CEN_HEADER_SIZE) + 1; - // Helps SparseOutputStream detect write of the last CEN entry - private static final String LAST_CEN_COMMENT = "LastCEN"; - private static final byte[] LAST_CEN_COMMENT_BYTES = LAST_CEN_COMMENT.getBytes(StandardCharsets.UTF_8); - // Expected ZipException message when the CEN does not fit in a Java byte array private static final String CEN_TOO_LARGE_MESSAGE = "invalid END header (central directory size too large)"; // Zip file to create for testing private File hugeZipFile; + private static final byte[] EXTRA_BYTES = makeLargeExtraField(); + // Helps SparseOutputStream detect write of the last CEN entry + private static final byte[] LAST_EXTRA_BYTES = makeLargeExtraField(); + /** * Create a zip file with a CEN size which does not fit within a Java byte array */ @@ -125,23 +123,18 @@ public void setup() throws IOException { // Set the time/date field for faster processing entry.setTimeLocal(TIME_LOCAL); - if (i == NUM_ENTRIES -1) { - // Help SparseOutputStream detect the last CEN entry write - entry.setComment(LAST_CEN_COMMENT); - } // Add the entry zip.putNextEntry(entry); - - } // Finish writing the last entry zip.closeEntry(); // Before the CEN headers are written, set the extra data on each entry - byte[] extra = makeLargeExtraField(); for (ZipEntry entry : entries) { - entry.setExtra(extra); + entry.setExtra(EXTRA_BYTES); } + // Help SparseOutputSream detect the last entry + entries[entries.length-1].setExtra(LAST_EXTRA_BYTES); } } @@ -165,7 +158,7 @@ public void centralDirectoryTooLargeToFitInByteArray() { * Data Size (Two byte short) * Data Block (Contents depend on field type) */ - private byte[] makeLargeExtraField() { + private static byte[] makeLargeExtraField() { // Make a maximally sized extra field byte[] extra = new byte[MAX_EXTRA_FIELD_SIZE]; // Little-endian ByteBuffer for updating the header fields @@ -203,7 +196,7 @@ public void write(byte[] b, int off, int len) throws IOException { // but instead simply advance the position, creating a sparse file channel.position(position); // Check for last CEN record - if (Arrays.equals(LAST_CEN_COMMENT_BYTES, 0, LAST_CEN_COMMENT_BYTES.length, b, off, len)) { + if (b == LAST_EXTRA_BYTES) { // From here on, write actual bytes sparse = false; } diff --git a/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java new file mode 100644 index 0000000000000..a083daf766871 --- /dev/null +++ b/test/jdk/java/util/zip/ZipFile/ReadAfterClose.java @@ -0,0 +1,128 @@ +/* + * 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 + @bug 8340684 + @summary Verify unspecified, but long-standing behavior when reading + from an input stream obtained using ZipFile::getInputStream after + the ZipFile has been closed. + @run junit ReadAfterClose + */ + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.stream.Stream; +import java.util.zip.CRC32; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class ReadAfterClose { + + // ZIP file used in this test + private Path zip = Path.of("read-after-close.zip"); + + /** + * Create a sample ZIP file for use by this test + * @throws IOException if an unexpected IOException occurs + */ + @BeforeEach + public void setUp() throws IOException { + byte[] content = "hello".repeat(1000).getBytes(StandardCharsets.UTF_8); + try (OutputStream out = Files.newOutputStream(zip); + ZipOutputStream zo = new ZipOutputStream(out)) { + { + zo.putNextEntry(new ZipEntry("deflated.txt")); + zo.write(content); + } + { + ZipEntry entry = new ZipEntry("stored.txt"); + entry.setMethod(ZipEntry.STORED); + CRC32 crc = new CRC32(); + crc.update(content); + entry.setCrc(crc.getValue()); + entry.setSize(content.length); + zo.putNextEntry(entry); + zo.write(content); + } + } + } + + /** + * Delete the ZIP file produced by this test + * @throws IOException if an unexpected IOException occurs + */ + @AfterEach + public void cleanup() throws IOException { + Files.deleteIfExists(zip); + } + + /** + * Produce arguments with a variation of stored / deflated entries, + * and read behavior before closing the ZipFile. + * @return + */ + public static Stream arguments() { + return Stream.of( + Arguments.of("stored.txt", true), + Arguments.of("stored.txt", false), + Arguments.of("deflated.txt", true), + Arguments.of("deflated.txt", false) + ); + } + /** + * Attempting to read from an InputStream obtained by ZipFile.getInputStream + * after the backing ZipFile is closed should throw IOException + * + * @throws IOException if an unexpected IOException occurs + */ + @ParameterizedTest + @MethodSource("arguments") + public void readAfterClose(String entryName, boolean readFirst) throws IOException { + // Retain a reference to an input stream backed by a closed ZipFile + InputStream in; + try (ZipFile zf = new ZipFile(zip.toFile())) { + in = zf.getInputStream(new ZipEntry(entryName)); + // Optionally consume a single byte from the stream before closing + if (readFirst) { + in.read(); + } + } + + assertThrows(IOException.class, () -> { + in.read(); + }); + } +} \ No newline at end of file diff --git a/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java b/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java new file mode 100644 index 0000000000000..286e043c2256f --- /dev/null +++ b/test/jdk/java/util/zip/ZipOutputStream/ZipOutputStreamMaxCenHdrTest.java @@ -0,0 +1,169 @@ +/* + * 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 + * @bug 8336025 + * @summary Verify that ZipOutputStream throws a ZipException when the + * CEN header size + name length + comment length + extra length exceeds + * 65,535 bytes + * @run junit ZipOutputStreamMaxCenHdrTest + */ +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import java.io.*; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Arrays; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +import static org.junit.jupiter.api.Assertions.*; + +public class ZipOutputStreamMaxCenHdrTest { + + // CEN header size + name length + comment length + extra length + // should not exceed 65,535 bytes per the PKWare APP.NOTE + // 4.4.10, 4.4.11, & 4.4.12. + static final int MAX_COMBINED_CEN_HEADER_SIZE = 0xFFFF; + + // Maximum possible size of name length + comment length + extra length + // for entries in order to not exceed 65,489 bytes minus 46 bytes for the CEN + // header length + static final int MAX_NAME_COMMENT_EXTRA_SIZE = + MAX_COMBINED_CEN_HEADER_SIZE - ZipFile.CENHDR; + + // Tag for the 'unknown' field type, specified in APPNOTE.txt 'Third party mappings' + static final short UNKNOWN_ZIP_TAG = (short) 0x9902; + + // ZIP file to be used by the tests + static final Path ZIP_FILE = Path.of("maxCENHdrTest.zip"); + + /** + * Clean up prior to test run + * + * @throws IOException if an error occurs + */ + @BeforeEach + public void startUp() throws IOException { + Files.deleteIfExists(ZIP_FILE); + } + + /** + * Validate a ZipException is thrown when the combined CEN Header, name + * length, comment length, and extra data length exceeds 65,535 bytes when + * the ZipOutputStream is closed. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_COMBINED_CEN_HEADER_SIZE - 1, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE - 1}) + void setCommentTest(int length) throws IOException { + boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; + final byte[] bytes = new byte[length]; + Arrays.fill(bytes, (byte) 'a'); + ZipEntry zipEntry = new ZipEntry(""); + // The comment length will trigger the ZipException + zipEntry.setComment(new String(bytes, StandardCharsets.UTF_8)); + boolean receivedException = writeZipEntry(zipEntry, expectZipException); + assertEquals(receivedException, expectZipException); + } + + /** + * Validate an ZipException is thrown when the combined CEN Header, name + * length, comment length, and extra data length exceeds 65,535 bytes when + * the ZipOutputStream is closed. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_COMBINED_CEN_HEADER_SIZE - 1, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE - 1}) + void setNameTest(int length) throws IOException { + boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; + final byte[] bytes = new byte[length]; + Arrays.fill(bytes, (byte) 'a'); + // The name length will trigger the ZipException + ZipEntry zipEntry = new ZipEntry(new String(bytes, StandardCharsets.UTF_8)); + boolean receivedException = writeZipEntry(zipEntry, expectZipException); + assertEquals(receivedException, expectZipException); + } + + /** + * Validate an ZipException is thrown when the combined CEN Header, name + * length, comment length, and extra data length exceeds 65,535 bytes when + * the ZipOutputStream is closed. + */ + @ParameterizedTest + @ValueSource(ints = {MAX_COMBINED_CEN_HEADER_SIZE, + MAX_COMBINED_CEN_HEADER_SIZE - 1, + MAX_NAME_COMMENT_EXTRA_SIZE, + MAX_NAME_COMMENT_EXTRA_SIZE - 1}) + void setExtraTest(int length) throws IOException { + boolean expectZipException = length > MAX_NAME_COMMENT_EXTRA_SIZE; + final byte[] bytes = new byte[length]; + // Little-endian ByteBuffer for updating the header fields + ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); + // We use the 'unknown' tag, specified in APPNOTE.TXT, 4.6.1 Third party mappings' + buffer.putShort(UNKNOWN_ZIP_TAG); + // Size of the actual (empty) data + buffer.putShort((short) (length - 2 * Short.BYTES)); + ZipEntry zipEntry = new ZipEntry(""); + // The extra data length will trigger the ZipException + zipEntry.setExtra(bytes); + boolean receivedException = writeZipEntry(zipEntry, expectZipException); + assertEquals(receivedException, expectZipException); + } + + /** + * Write a single Zip entry using ZipOutputStream + * @param zipEntry the ZipEntry to write + * @param expectZipException true if a ZipException is expected, false otherwse + * @return true if a ZipException was thrown + * @throws IOException if an error occurs + */ + private static boolean writeZipEntry(ZipEntry zipEntry, boolean expectZipException) + throws IOException { + boolean receivedException = false; + try (ZipOutputStream zos = new ZipOutputStream( + new BufferedOutputStream(Files.newOutputStream(ZIP_FILE)))) { + zos.putNextEntry(zipEntry); + if (expectZipException) { + ZipException ex = assertThrows(ZipException.class, zos::close); + assertTrue(ex.getMessage().matches(".*bad header size.*"), + "Unexpected ZipException message: " + ex.getMessage()); + receivedException = true; + } + } catch (Exception e) { + throw new RuntimeException("Received Unexpected Exception", e); + } + return receivedException; + } +} diff --git a/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java index 7c97c9dd5a9b1..b5d3ba5d584fb 100644 --- a/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java +++ b/test/jdk/jdk/classfile/ConstantDescSymbolsTest.java @@ -23,11 +23,14 @@ /* * @test - * @bug 8304031 8338406 + * @bug 8304031 8338406 8338546 * @summary Testing handling of various constant descriptors in ClassFile API. + * @modules java.base/jdk.internal.constant + * java.base/jdk.internal.classfile.impl * @run junit ConstantDescSymbolsTest */ +import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.constant.ClassDesc; import java.lang.constant.DynamicConstantDesc; import java.lang.constant.MethodHandleDesc; @@ -36,8 +39,14 @@ import java.lang.invoke.MethodType; import java.util.function.Supplier; import java.lang.classfile.ClassFile; +import java.util.stream.Stream; + +import jdk.internal.classfile.impl.AbstractPoolEntry; +import jdk.internal.constant.ConstantUtils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; import static java.lang.classfile.ClassFile.ACC_PUBLIC; import static java.lang.constant.ConstantDescs.*; @@ -102,4 +111,58 @@ record CondyBoot(MethodHandles.Lookup lookup, String name, Class type) {} assertEquals(DEFAULT_NAME, cb.name); assertEquals(CondyBoot.class, cb.type); } + + static Stream classOrInterfaceEntries() { + return Stream.of( + CD_Object, CD_Float, CD_Long, CD_String, ClassDesc.of("Ape"), + CD_String.nested("Whatever"), CD_MethodHandles_Lookup, ClassDesc.ofInternalName("one/Two"), + ClassDesc.ofDescriptor("La/b/C;"), ConstantDescSymbolsTest.class.describeConstable().orElseThrow(), + CD_Boolean, CD_ConstantBootstraps, CD_MethodHandles + ); + } + + @ParameterizedTest + @MethodSource("classOrInterfaceEntries") + void testConstantPoolBuilderClassOrInterfaceEntry(ClassDesc cd) { + assertTrue(cd.isClassOrInterface()); + ConstantPoolBuilder cp = ConstantPoolBuilder.of(); + var internal = ConstantUtils.dropFirstAndLastChar(cd.descriptorString()); + + // 1. ClassDesc + var ce = cp.classEntry(cd); + assertSame(cd, ce.asSymbol(), "Symbol propagation on create"); + + // 1.1. Bare addition + assertTrue(ce.name().equalsString(internal), "Adding to bare pool"); + + // 1.2. Lookup existing + assertSame(ce, cp.classEntry(cd), "Finding by identical CD"); + + // 1.3. Lookup existing - equal but different ClassDesc + var cd1 = ClassDesc.ofDescriptor(cd.descriptorString()); + assertSame(ce, cp.classEntry(cd1), "Finding by another equal CD"); + + // 1.3.1. Lookup existing - equal but different ClassDesc, equal but different string + var cd2 = ClassDesc.ofDescriptor("" + cd.descriptorString()); + assertSame(ce, cp.classEntry(cd2), "Finding by another equal CD"); + + // 1.4. Lookup existing - with utf8 internal name + var utf8 = cp.utf8Entry(internal); + assertSame(ce, cp.classEntry(utf8), "Finding CD by UTF8"); + + // 2. ClassEntry exists, no ClassDesc + cp = ConstantPoolBuilder.of(); + utf8 = cp.utf8Entry(internal); + ce = cp.classEntry(utf8); + var found = cp.classEntry(cd); + assertSame(ce, found, "Finding non-CD CEs with CD"); + assertEquals(cd, ce.asSymbol(), "Symbol propagation on find"); + + // 3. Utf8Entry exists, no ClassEntry + cp = ConstantPoolBuilder.of(); + utf8 = cp.utf8Entry(internal); + ce = cp.classEntry(cd); + assertSame(utf8, ce.name(), "Reusing existing utf8 entry"); + assertEquals(cd, ce.asSymbol(), "Symbol propagation on create with utf8"); + } } diff --git a/test/jdk/jdk/classfile/LimitsTest.java b/test/jdk/jdk/classfile/LimitsTest.java index 9c7b8d9e72d4a..a1899ac1c842b 100644 --- a/test/jdk/jdk/classfile/LimitsTest.java +++ b/test/jdk/jdk/classfile/LimitsTest.java @@ -28,6 +28,7 @@ * @run junit LimitsTest */ import java.lang.classfile.Attributes; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; import java.lang.constant.ConstantDescs; import java.lang.constant.MethodTypeDesc; @@ -36,12 +37,10 @@ import java.lang.classfile.attribute.CodeAttribute; import java.lang.classfile.attribute.LineNumberInfo; import java.lang.classfile.attribute.LineNumberTableAttribute; -import java.lang.classfile.attribute.LocalVariableInfo; import java.lang.classfile.attribute.LocalVariableTableAttribute; import java.lang.classfile.constantpool.ConstantPoolBuilder; import java.lang.classfile.constantpool.ConstantPoolException; import java.lang.classfile.constantpool.IntegerEntry; -import java.lang.classfile.instruction.LocalVariable; import java.util.List; import jdk.internal.classfile.impl.BufWriterImpl; @@ -113,13 +112,13 @@ void testReadingOutOfBounds() { @Test void testInvalidClassEntry() { assertThrows(ConstantPoolException.class, () -> ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 2, ClassFile.TAG_METHODREF, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).thisClass()); + 0, 0, 0, 0, 0, 2, PoolEntry.TAG_METHODREF, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).thisClass()); } @Test void testInvalidUtf8Entry() { var cp = ClassFile.of().parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 3, ClassFile.TAG_INTEGER, 0, 0, 0, 0, ClassFile.TAG_NAMEANDTYPE, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).constantPool(); + 0, 0, 0, 0, 0, 3, PoolEntry.TAG_INTEGER, 0, 0, 0, 0, PoolEntry.TAG_NAME_AND_TYPE, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}).constantPool(); assertTrue(cp.entryByIndex(1) instanceof IntegerEntry); //parse valid int entry first assertThrows(ConstantPoolException.class, () -> cp.entryByIndex(2)); } diff --git a/test/jdk/jdk/classfile/StackMapsTest.java b/test/jdk/jdk/classfile/StackMapsTest.java index 09be56f0de2a1..1ccd7255ed4b9 100644 --- a/test/jdk/jdk/classfile/StackMapsTest.java +++ b/test/jdk/jdk/classfile/StackMapsTest.java @@ -385,9 +385,9 @@ void testDeadCodeCountersWithCustomSMTA() { StackMapTableAttribute.of(List.of( StackMapFrameInfo.of(f2, List.of(), - List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG)), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.LONG)), StackMapFrameInfo.of(f3, - List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.ITEM_LONG), + List.of(StackMapFrameInfo.SimpleVerificationTypeInfo.LONG), List.of())))); } )); diff --git a/test/jdk/jdk/classfile/UtilTest.java b/test/jdk/jdk/classfile/UtilTest.java index d9d8240ae9149..be66d9305808c 100644 --- a/test/jdk/jdk/classfile/UtilTest.java +++ b/test/jdk/jdk/classfile/UtilTest.java @@ -23,18 +23,25 @@ /* * @test + * @bug 8338546 * @summary Testing ClassFile Util. + * @library java.base + * @modules java.base/jdk.internal.constant + * java.base/jdk.internal.classfile.impl + * @build java.base/jdk.internal.classfile.impl.* * @run junit UtilTest */ -import java.lang.classfile.ClassFile; import java.lang.classfile.Opcode; import java.lang.constant.MethodTypeDesc; -import java.lang.invoke.MethodHandles; import java.util.Arrays; -import java.util.BitSet; +import java.util.concurrent.CopyOnWriteArrayList; +import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + import jdk.internal.classfile.impl.RawBytecodeHelper; import jdk.internal.classfile.impl.Util; +import jdk.internal.classfile.impl.UtilAccess; +import jdk.internal.constant.ConstantUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -84,6 +91,50 @@ private void assertSlots(String methodDesc, int slots) { assertEquals(Util.parameterSlots(MethodTypeDesc.ofDescriptor(methodDesc)), slots); } + @Test + void testPow31() { + int p = 1; + // Our calculation only prepares up to 65536, + // max length of CP Utf8 + 1 + for (int i = 0; i <= 65536; i++) { + final int t = i; + assertEquals(p, Util.pow31(i), () -> "31's power to " + t); + p *= 31; + } + } + + @ParameterizedTest + @ValueSource(classes = { + Long.class, + Object.class, + Util.class, + Test.class, + CopyOnWriteArrayList.class, + AtomicReferenceFieldUpdater.class + }) + void testInternalNameHash(Class type) { + var cd = type.describeConstable().orElseThrow(); + assertEquals(ConstantUtils.binaryToInternal(type.getName()).hashCode(), Util.internalNameHash(cd.descriptorString())); + } + + // Ensures the initialization statement of the powers array is filling in the right values + @Test + void testPowersArray() { + int[] powers = new int[7 * UtilAccess.significantOctalDigits()]; + for (int i = 1, k = 31; i <= 7; i++, k *= 31) { + int t = powers[UtilAccess.powersIndex(i, 0)] = k; + + for (int j = 1; j < UtilAccess.significantOctalDigits(); j++) { + t *= t; + t *= t; + t *= t; + powers[UtilAccess.powersIndex(i, j)] = t; + } + } + + assertArrayEquals(powers, UtilAccess.powersTable()); + } + @Test void testOpcodeLengthTable() { var lengths = new byte[0x100]; diff --git a/test/jdk/jdk/classfile/VerifierSelfTest.java b/test/jdk/jdk/classfile/VerifierSelfTest.java index d0943d2eee9f5..b6a2f08c9ecd7 100644 --- a/test/jdk/jdk/classfile/VerifierSelfTest.java +++ b/test/jdk/jdk/classfile/VerifierSelfTest.java @@ -29,6 +29,7 @@ * @run junit VerifierSelfTest */ import java.io.IOException; +import java.lang.classfile.constantpool.PoolEntry; import java.lang.constant.ClassDesc; import static java.lang.constant.ConstantDescs.*; import java.lang.invoke.MethodHandleInfo; @@ -116,7 +117,7 @@ public void writeBody(BufWriterImpl b) { void testInvalidClassNameEntry() { var cc = ClassFile.of(); var bytes = cc.parse(new byte[]{(byte)0xCA, (byte)0xFE, (byte)0xBA, (byte)0xBE, - 0, 0, 0, 0, 0, 2, ClassFile.TAG_INTEGER, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); + 0, 0, 0, 0, 0, 2, PoolEntry.TAG_INTEGER, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}); assertTrue(cc.verify(bytes).stream().anyMatch(e -> e.getMessage().contains("expected ClassEntry"))); } diff --git a/test/jdk/jdk/classfile/helpers/ClassRecord.java b/test/jdk/jdk/classfile/helpers/ClassRecord.java index 329e41fa0f484..e7a239015f605 100644 --- a/test/jdk/jdk/classfile/helpers/ClassRecord.java +++ b/test/jdk/jdk/classfile/helpers/ClassRecord.java @@ -22,21 +22,13 @@ */ package helpers; -import java.io.IOException; -import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.RecordComponent; import java.math.BigInteger; import java.nio.charset.StandardCharsets; -import java.nio.file.Path; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.NoSuchElementException; import java.util.Objects; import java.util.Set; import java.util.function.Function; @@ -53,9 +45,10 @@ import static java.util.stream.Collectors.toMap; import static java.util.stream.Collectors.toSet; -import static java.lang.classfile.ClassFile.*; import static java.lang.classfile.Attributes.*; +import static java.lang.classfile.constantpool.PoolEntry.*; import static helpers.ClassRecord.CompatibilityFilter.By_ClassBuilder; +import static jdk.internal.classfile.impl.RawBytecodeHelper.*; /** * ClassRecord @@ -916,17 +909,17 @@ public static ConstantPoolEntryRecord ofCPEntry(PoolEntry cpInfo) { CpFieldRefRecord.ofFieldRefEntry((FieldRefEntry) cpInfo); case TAG_METHODREF -> CpMethodRefRecord.ofMethodRefEntry((MethodRefEntry) cpInfo); - case TAG_INTERFACEMETHODREF -> + case TAG_INTERFACE_METHODREF -> CpInterfaceMethodRefRecord.ofInterfaceMethodRefEntry((InterfaceMethodRefEntry) cpInfo); - case TAG_NAMEANDTYPE -> + case TAG_NAME_AND_TYPE -> CpNameAndTypeRecord.ofNameAndTypeEntry((NameAndTypeEntry) cpInfo); - case TAG_METHODHANDLE -> + case TAG_METHOD_HANDLE -> CpMethodHandleRecord.ofMethodHandleEntry((MethodHandleEntry) cpInfo); - case TAG_METHODTYPE -> + case TAG_METHOD_TYPE -> new CpMethodTypeRecord(((MethodTypeEntry) cpInfo).descriptor().stringValue()); - case TAG_CONSTANTDYNAMIC -> + case TAG_DYNAMIC -> CpConstantDynamicRecord.ofConstantDynamicEntry((ConstantDynamicEntry) cpInfo); - case TAG_INVOKEDYNAMIC -> + case TAG_INVOKE_DYNAMIC -> CpInvokeDynamicRecord.ofInvokeDynamicEntry((InvokeDynamicEntry) cpInfo); case TAG_MODULE -> new CpModuleRecord(((ModuleEntry) cpInfo).name().stringValue()); diff --git a/test/jdk/jdk/classfile/java.base/jdk/internal/classfile/impl/UtilAccess.java b/test/jdk/jdk/classfile/java.base/jdk/internal/classfile/impl/UtilAccess.java new file mode 100644 index 0000000000000..27cefd6d9441a --- /dev/null +++ b/test/jdk/jdk/classfile/java.base/jdk/internal/classfile/impl/UtilAccess.java @@ -0,0 +1,41 @@ +/* + * 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. + */ +package jdk.internal.classfile.impl; + +public final class UtilAccess { + public static int significantOctalDigits() { + return Util.SIGNIFICANT_OCTAL_DIGITS; + } + + public static int powersIndex(int digit, int index) { + return Util.powersIndex(digit, index); + } + + public static int[] powersTable() { + return Util.powers; + } + + public static int reverse31() { + return Util.INVERSE_31; + } +} diff --git a/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java index 32c634fc59a90..daf562a765fbe 100644 --- a/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java +++ b/test/jdk/jdk/jfr/event/compiler/TestDeoptimization.java @@ -53,6 +53,7 @@ public static void dummyMethod(boolean b) { * @requires vm.hasJFR * @requires vm.compMode != "Xint" * @requires vm.flavor == "server" & (vm.opt.TieredStopAtLevel == 4 | vm.opt.TieredStopAtLevel == null) + * @requires vm.opt.StressUnstableIfTraps == null | !vm.opt.StressUnstableIfTraps * @library /test/lib * @build jdk.test.whitebox.WhiteBox * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox diff --git a/test/jdk/sun/awt/image/BytePackedRaster/DitherTest.java b/test/jdk/sun/awt/image/BytePackedRaster/DitherTest.java new file mode 100644 index 0000000000000..29b42b49fe778 --- /dev/null +++ b/test/jdk/sun/awt/image/BytePackedRaster/DitherTest.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4184283 + * @summary Checks rendering of dithered byte packed image does not crash. + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.IndexColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.WritableRaster; + +public class DitherTest extends Component { + + final static int NOOP = 0; + final static int RED = 1; + final static int GREEN = 2; + final static int BLUE = 3; + final static int ALPHA = 4; + final static int SATURATION = 5; + + final static byte red[] = {(byte)0, (byte)132, (byte)0, (byte)132, (byte)0, (byte)132, + (byte)0, (byte)198, (byte)198, (byte)165, (byte)255, (byte)165, (byte)132, + (byte)255, (byte)0, (byte)255}; + + final static byte green[] = {(byte)0, (byte)0, (byte)130, (byte)130, (byte)0, + (byte)0, (byte)130, (byte)195, (byte)223, (byte)203, (byte)251, (byte)162, + (byte)132, (byte)0, (byte)255, (byte)255}; + + final static byte blue[] = {(byte)0, (byte)0, (byte)0, (byte)0, (byte)132, (byte)132, + (byte)132, (byte)198, (byte)198, (byte)247, (byte)247, (byte)165, (byte)132, + (byte)0, (byte)0, (byte)0}; + + static IndexColorModel cm16 = new IndexColorModel( 4, 16, red, green, blue); + + + public static void main(String args[]) { + + int imageWidth = 256; + int imageHeight = 256; + WritableRaster raster = cm16.createCompatibleWritableRaster(imageWidth, imageHeight); + BufferedImage intermediateImage = new BufferedImage(cm16, raster, false, null); + Image calculatedImage = calculateImage(); + + Graphics2D ig = intermediateImage.createGraphics(); + // Clear background and fill a red rectangle just to prove that we can draw on intermediateImage + ig.setColor(Color.white); + ig.fillRect(0,0,imageWidth,imageHeight); + ig.drawImage(calculatedImage, 0, 0, imageWidth, imageHeight, null); + ig.setColor(Color.red); + ig.fillRect(0,0,5,5); + + BufferedImage destImage = new BufferedImage(imageWidth, imageWidth, BufferedImage.TYPE_INT_RGB); + Graphics2D dg = destImage.createGraphics(); + dg.drawImage(intermediateImage, 0, 0, imageWidth, imageHeight, null); + } + + private static void applymethod(int c[], int method, int step, int total, int vals[]) { + if (method == NOOP) + return; + int val = ((total < 2) + ? vals[0] + : vals[0] + ((vals[1] - vals[0]) * step / (total - 1))); + switch (method) { + case RED: + c[0] = val; + break; + case GREEN: + c[1] = val; + break; + case BLUE: + c[2] = val; + break; + case ALPHA: + c[3] = val; + break; + case SATURATION: + int max = Math.max(Math.max(c[0], c[1]), c[2]); + int min = max * (255 - val) / 255; + if (c[0] == 0) c[0] = min; + if (c[1] == 0) c[1] = min; + if (c[2] == 0) c[2] = min; + break; + } + } + + private static Image calculateImage() { + + int xvals[] = { 0, 255 }; + int yvals[] = { 0, 255 }; + int xmethod = RED; + int ymethod = BLUE; + int width = 256; + int height = 256; + int pixels[] = new int[width * height]; + int c[] = new int[4]; + int index = 0; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + c[0] = c[1] = c[2] = 0; + c[3] = 255; + if (xmethod < ymethod) { + applymethod(c, xmethod, i, width, xvals); + applymethod(c, ymethod, j, height, yvals); + } else { + applymethod(c, ymethod, j, height, yvals); + applymethod(c, xmethod, i, width, xvals); + } + pixels[index++] = ((c[3] << 24) | + (c[0] << 16) | + (c[1] << 8) | + (c[2] << 0)); + } + } + + DitherTest dt = new DitherTest(); + return dt.createImage(new MemoryImageSource(width, height, ColorModel.getRGBdefault(), pixels, 0, width)); + } +} + diff --git a/test/jdk/sun/awt/image/BytePackedRaster/MultiOp.java b/test/jdk/sun/awt/image/BytePackedRaster/MultiOp.java new file mode 100644 index 0000000000000..2c396792548f2 --- /dev/null +++ b/test/jdk/sun/awt/image/BytePackedRaster/MultiOp.java @@ -0,0 +1,108 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4213160 + * @summary Should generate a black image + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.IndexColorModel; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.awt.geom.AffineTransform; + +public class MultiOp { + + public static void main(String[] argv) { + + int width = 256; + int height = 256; + + int pixelBits = 2; // 1, 2, 4, or 8 + // 1 and 8 make the code throw ImagingOpException, 2 and 4 + // make the code SEGV on Sol. + + byte[] lut1Arr = new byte[] {0, (byte)255 }; + byte[] lut2Arr = new byte[] {0, (byte)85, (byte)170, (byte)255}; + byte[] lut4Arr = new byte[] {0, (byte)17, (byte)34, (byte)51, + (byte)68, (byte)85,(byte) 102, (byte)119, + (byte)136, (byte)153, (byte)170, (byte)187, + (byte)204, (byte)221, (byte)238, (byte)255}; + byte[] lut8Arr = new byte[256]; + for (int i = 0; i < 256; i++) { + lut8Arr[i] = (byte)i; + } + + // Create the binary image + int bytesPerRow = width * pixelBits / 8; + byte[] imageData = new byte[height * bytesPerRow]; + ColorModel cm = null; + + switch (pixelBits) { + case 1: + cm = new IndexColorModel(pixelBits, lut1Arr.length, + lut1Arr, lut1Arr, lut1Arr); + break; + case 2: + cm = new IndexColorModel(pixelBits, lut2Arr.length, + lut2Arr, lut2Arr, lut2Arr); + break; + case 4: + cm = new IndexColorModel(pixelBits, lut4Arr.length, + lut4Arr, lut4Arr, lut4Arr); + break; + case 8: + cm = new IndexColorModel(pixelBits, lut8Arr.length, + lut8Arr, lut8Arr, lut8Arr); + break; + default: + {new Exception("Invalid # of bit per pixel").printStackTrace();} + } + + DataBuffer db = new DataBufferByte(imageData, imageData.length); + WritableRaster r = Raster.createPackedRaster(db, width, height, + pixelBits, null); + BufferedImage srcImage = new BufferedImage(cm, r, false, null); + + BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + Graphics2D g = destImage.createGraphics(); + AffineTransform af = AffineTransform.getScaleInstance(.5, .5); + // This draw image is the problem + g.drawImage(srcImage, af, null); + int blackPixel = Color.black.getRGB(); + for (int x = 0; x < width; x++) { + for (int y = 0; y < height; y++) { + if (destImage.getRGB(x, y) != blackPixel) { + throw new RuntimeException("Not black"); + } + } + } + } +} diff --git a/test/jdk/sun/awt/image/ImageRepresentation/ByteBinaryBitmask.java b/test/jdk/sun/awt/image/ImageRepresentation/ByteBinaryBitmask.java new file mode 100644 index 0000000000000..26edca7f09b72 --- /dev/null +++ b/test/jdk/sun/awt/image/ImageRepresentation/ByteBinaryBitmask.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2002, 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 + * @bug 4673490 + * @summary This test verifies that Toolkit images with a 1-bit + * IndexColorModel (known as ByteBinary) and a transparent index are rendered properly. + */ + +import java.awt.Color; +import java.awt.Graphics2D; + +import java.awt.image.BufferedImage; +import java.awt.image.IndexColorModel; + +public class ByteBinaryBitmask { + + public static void main(String argv[]) throws Exception { + + /* Create the image */ + int w = 16, h = 16; + byte[] bw = { (byte)255, (byte)0, }; + IndexColorModel icm = new IndexColorModel(1, 2, bw, bw, bw, 0); + BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_BINARY, icm); + Graphics2D g2d = img.createGraphics(); + g2d.setColor(Color.white); + g2d.fillRect(0, 0, w, h); + g2d.setColor(Color.black); + int xoff = 5; + g2d.fillRect(xoff, 5, 1, 10); // 1 pixel wide + + int dw = 200, dh = 50; + BufferedImage dest = new BufferedImage(dw, dh, BufferedImage.TYPE_INT_RGB); + Graphics2D g = dest.createGraphics(); + g.setColor(Color.green); + g.fillRect(0, 0, dw, dh); + int x1 = 10; + int x2 = 50; + int x3 = 90; + int x4 = 130; + g.drawImage(img, x1, 10, null); + g.drawImage(img, x2, 10, null); + g.drawImage(img, x3, 10, null); + g.drawImage(img, x4, 10, null); + + int blackPix = Color.black.getRGB(); + for (int y = 0; y < dh; y++) { + boolean isBlack = false; + for (int x = 0; x < dw; x++) { + int rgb = dest.getRGB(x, y); + if (rgb == blackPix) { + /* Src image has a one pixel wide vertical rect at off "xoff" and + * this is drawn at x1/x2/x3/x4) so the sum of those are the x locations + * to expect black. + */ + if (x != (x1 + xoff) && x != (x2 + xoff) && x != (x3 + xoff) && x!= (x4 + xoff)) { + throw new RuntimeException("wrong x location: " +x); + } + if (isBlack) { + throw new RuntimeException("black after black"); + } + } + isBlack = rgb == blackPix; + } + } + } +} diff --git a/test/jdk/sun/awt/image/ImageRepresentation/CustomSourceCM.java b/test/jdk/sun/awt/image/ImageRepresentation/CustomSourceCM.java new file mode 100644 index 0000000000000..c56b4ef88c807 --- /dev/null +++ b/test/jdk/sun/awt/image/ImageRepresentation/CustomSourceCM.java @@ -0,0 +1,142 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4192756 + * @summary Tests that using a non-default colormodel generates correct images under 16/24 bit mode + */ + +import java.awt.Color; +import java.awt.Component; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.MemoryImageSource; +import java.util.Arrays; + +/* + * NOTE: This bug only appears under specific conditions. If the background of + * the surface is red, then you are not running under the conditions necessary + * to test for the regression so the results of this test will be inconclusive. + * + * The test should be run under any of the following screen depths/surfaces: + * + * 15-bit, otherwise known as 555 RGB or 32768 (thousands) colors + * 16-bit, otherwise known as 565 RGB or 65536 (thousands) colors + * 24-bit, otherwise known as 16777216 (millions) colors + * + * The test draws 2 rectangles. Both rectangles should be half black (left) + * and half blue (right). If the top rectangle is all black, the test fails. + * If the background is red, the results are inconclusive (see above). +*/ + +public class CustomSourceCM extends Component { + + public static int IMG_W = 80; + public static int IMG_H = 30; + + static void test(int imageType) { + + int w = IMG_W + 20; + int h = IMG_H * 2 + 40; + BufferedImage bi = new BufferedImage(w, h, imageType); + + DirectColorModel dcm; + + /* the next dozen lines or so are intended to help + * ascertain if the destination surface is of the type + * that exhibited the original bug, making the background + * white in those cases. It is not strictly necessary. + * It is only for a manual tester to be able to tell by looking. + * The real test is the check for black and blue later on. + */ + Graphics2D g = bi.createGraphics(); + g.setColor(Color.red); + g.fillRect(0, 0, w, h); + + ColorModel cm = bi.getColorModel(); + if (cm instanceof ComponentColorModel) { + g.setColor(Color.white); + g.fillRect(0, 0, w, h); + } else if (cm instanceof DirectColorModel) { + dcm = (DirectColorModel) cm; + if (dcm.getPixelSize() < 24) { + g.setColor(Color.white); + g.fillRect(0, 0, w, h); + } + } + + // Construct a ColorModel and data for a 16-bit 565 image... + dcm = new DirectColorModel(16, 0x1f, 0x7e0, 0xf800); + + // Create an image which is black on the left, blue on the right. + int[] pixels = new int[IMG_W * IMG_H]; + int blue = dcm.getBlueMask(); + int off = 0; + for (int y = 0; y < IMG_H; y++) { + Arrays.fill(pixels, off, off+IMG_W/2, 0); + Arrays.fill(pixels, off+IMG_W/2, off+IMG_W, blue); + off += IMG_W; + } + MemoryImageSource mis = new MemoryImageSource(IMG_W, IMG_H, dcm, + pixels, 0, IMG_W); + CustomSourceCM comp = new CustomSourceCM(); + Image img = comp.createImage(mis); + + // Draw the image on to the surface. + g.drawImage(img, 10, 10, null); + + // Create a similar effect with 2 fillrects, below the image. + g.setColor(Color.black); + g.fillRect(10, 60, IMG_W/2, IMG_H); + g.setColor(Color.blue); + g.fillRect(10+IMG_W/2, 60, IMG_W/2, IMG_H); + + // Now sample points in the image to confirm they are the expected color. + int bluePix = Color.blue.getRGB(); + int blackPix = Color.black.getRGB(); + int black_topLeft = bi.getRGB(10+IMG_W/4, 10+IMG_H/2); + int blue_topRight = bi.getRGB(10+IMG_W*3/4, 10+IMG_H/2); + int black_bottomLeft = bi.getRGB(10+IMG_W/4, 60+IMG_H/2); + int blue_bottomRight = bi.getRGB(10+IMG_W*3/4, 60+IMG_H/2); + if ((black_topLeft != blackPix) || (black_bottomLeft != blackPix) || + (blue_topRight != bluePix) || (blue_bottomRight != bluePix)) { + + String fileName = "failed " + imageType + ".png"; + try { + javax.imageio.ImageIO.write(bi, "png", new java.io.File(fileName)); + } catch (Exception e) { }; + throw new RuntimeException("unexpected colors"); + } + } + + public static void main(String argv[]) { + test(BufferedImage.TYPE_USHORT_555_RGB); + test(BufferedImage.TYPE_USHORT_565_RGB); + test(BufferedImage.TYPE_3BYTE_BGR); + } +} diff --git a/test/jdk/sun/java2d/loops/ARGBBgToRGB.java b/test/jdk/sun/java2d/loops/ARGBBgToRGB.java new file mode 100644 index 0000000000000..55764af2c1354 --- /dev/null +++ b/test/jdk/sun/java2d/loops/ARGBBgToRGB.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4238978 + * @summary This test verifies that the correct blitting loop is being used. + * The correct output should have a yellow border on the top and + * left sides of a red box. The incorrect output would have only + * a red box -- no yellow border." + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class ARGBBgToRGB { + + public static void main(String[] argv) { + BufferedImage bi = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB); + Graphics2D big = bi.createGraphics(); + big.setColor(Color.red); + big.fillRect(30, 30, 150, 150); + + BufferedImage bi2 = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB); + Graphics2D big2 = bi2.createGraphics(); + big2.drawImage(bi, 0, 0, Color.yellow, null); + + int expectYellowPix = bi2.getRGB(0, 0); + int expectRedPix = bi2.getRGB(50, 50); + if ((expectYellowPix != Color.yellow.getRGB()) || + (expectRedPix != Color.red.getRGB())) + { + throw new RuntimeException("Unexpected colors " + expectYellowPix + " " + expectRedPix); + } + } +} diff --git a/test/jdk/sun/java2d/loops/CopyNegative.java b/test/jdk/sun/java2d/loops/CopyNegative.java new file mode 100644 index 0000000000000..0b8296918ac63 --- /dev/null +++ b/test/jdk/sun/java2d/loops/CopyNegative.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4188744 + * @summary This test verifies that copyArea performs correctly for negative offset values. + * The correct output shows that the text area is moved to the left and down, + * leaving some garbage on the right and the top. + * The incorrect copy would show the text area garbled and no text is legible. + * @library /java/awt/regtesthelpers + * @build PassFailJFrame + * @run main/manual CopyNegative + */ + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Panel; + +public class CopyNegative extends Panel { + + private static final String INSTRUCTIONS = """ + This test verifies that copyArea performs correctly for negative offset values. + The test draws text in an image, then copies the contents repeatedly. + The correct output shows that the text is moved to the left and down, + leaving some garbage on the top / right and some legible text at the bottom left. + The incorrect copy would show the whole text area garbled and no text is legible. + """; + + public static void main(String[] argv) throws Exception { + PassFailJFrame.builder() + .title("CopyNegativeTest") + .instructions(INSTRUCTIONS) + .testUI(CopyNegative::createUI) + .testTimeOut(5) + .rows(10) + .columns(50) + .build() + .awaitAndCheck(); + } + + Image img; + + static final int W = 200, H = 200; + + static Frame createUI() { + Frame f = new Frame("CopyNegative"); + f.add(new CopyNegative()); + f.pack(); + return f; + } + + public Dimension getPreferredSize() { + return new Dimension(W, H); + } + + private void doCopy() { + Graphics g = img.getGraphics(); + g.setColor(Color.white); + g.fillRect(0, 0, W, H); + g.setColor(Color.black); + String text = "Some Text To Display, it is long enough to fill the entire display line."; + StringBuffer sb = new StringBuffer(text); + + for (int i = 1; i < 50; i++) { + g.drawString(sb.toString(), 5,20 * i - 10); + sb.insert(0, Integer.toString(i)); + } + for (int i = 0 ; i < 20 ; i++ ) { + g.copyArea(0, 0, W, H, -3, 3); + } + } + + public void paint(Graphics g) { + img = createImage(W, H); + doCopy(); + g.drawImage(img, 0, 0, this); + } + +} diff --git a/test/jdk/sun/java2d/loops/DitheredSolidFill.java b/test/jdk/sun/java2d/loops/DitheredSolidFill.java new file mode 100644 index 0000000000000..509b0bbe3b234 --- /dev/null +++ b/test/jdk/sun/java2d/loops/DitheredSolidFill.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4181172 + * @summary Confirm that solid white fill is not dithered on an 8-bit indexed surface. + * The test draws two areas filled with white solid color. + * The upper left square is filled in aliasing mode and + * the lower right square is filled in anti-aliasing mode. + */ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.image.BufferedImage; + +public class DitheredSolidFill { + + public static void main(String args[]) { + BufferedImage bi = new BufferedImage(120, 120, BufferedImage.TYPE_BYTE_INDEXED); + Graphics2D g2D = bi.createGraphics(); + + g2D.setColor(Color.black); + g2D.fillRect(0, 0, 100, 100); + + g2D.setColor(Color.white); + g2D.fillRect(5, 5, 40, 40); + checkPixels(bi, 5, 5, 40, 40); + + g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + g2D.fillRect(55, 55, 40, 40); + checkPixels(bi, 55, 55, 40, 40); + } + + static void checkPixels(BufferedImage bi, int x, int y, int w, int h) { + // pixel can be off white, but must be the same in all cases. + int expectedPix = bi.getRGB(x, y); + for (int x0 = x; x0 < x + w; x0++) { + for (int y0 = y; y0 < y + h; y0++) { + if (bi.getRGB(x0, y0) != expectedPix) { + try { + javax.imageio.ImageIO.write(bi, "png", new java.io.File("failed.png")); + } catch (Exception e) { + } + throw new RuntimeException("Not expected pix : " + + Integer.toHexString(bi.getRGB(x0, y0)) + + " at " + x0 + "," + y0); + } + } + } + } +} diff --git a/test/jdk/sun/java2d/loops/OffsetCalculationTest.java b/test/jdk/sun/java2d/loops/OffsetCalculationTest.java new file mode 100644 index 0000000000000..fe30107f22a9f --- /dev/null +++ b/test/jdk/sun/java2d/loops/OffsetCalculationTest.java @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1999, 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 + @bug 4236576 + @summary tests that a BufferedImage in TYPE_3BYTE_BGR format is correctly + drawn when there is an offset between the Graphics clip bounds + and the clip box of the underlying device context. + @run main OffsetCalculationTest +*/ + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.DataBuffer; + +public class OffsetCalculationTest { + + public static void main(String[] args) { + BufferedImage srcImage = new BufferedImage(500, 500, BufferedImage.TYPE_3BYTE_BGR); + + DataBuffer buffer = srcImage.getRaster().getDataBuffer(); + for (int i = 2; i < buffer.getSize(); i+=3) { + // setting each pixel to blue via the data buffer elements. + buffer.setElem(i - 2, 0xff); + buffer.setElem(i - 1, 0); + buffer.setElem(i, 0); + } + + int w = 200, h = 200; + BufferedImage destImage = new BufferedImage(w, h, BufferedImage.TYPE_3BYTE_BGR); + Graphics2D g = destImage.createGraphics(); + Rectangle r = new Rectangle(0, 0, w, h); + g.setClip(r.x - 1, r.y, r.width + 1, r.height); + g.drawImage(srcImage, 0, 0, null); + + int bluepix = Color.blue.getRGB(); + for (int y = 0; y < w; y++) { + for (int x = 0; x < h; x++) { + if (destImage.getRGB(x, y) != bluepix) { + throw new RuntimeException("Not Blue"); + } + } + } + } +} diff --git a/test/jdk/sun/java2d/loops/XORClearRect.java b/test/jdk/sun/java2d/loops/XORClearRect.java new file mode 100644 index 0000000000000..f5c30581cf1f3 --- /dev/null +++ b/test/jdk/sun/java2d/loops/XORClearRect.java @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 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 + * @bug 4088173 + * @summary This interactive test verifies that the XOR mode is not affecting + * the clearRect() call. The correct output looks like: + * + * \ / + * \ / + * The backgound is blue. + * The lines outside the central rectangle are green. + * The central rectangle is also blue (the result of clearRect()) + * / \ + * / \ + * + * @key headful + * @run main XORClearRect + */ + +import java.awt.Color; +import java.awt.EventQueue; +import java.awt.Graphics; +import java.awt.Frame; +import java.awt.Panel; +import java.awt.Point; +import java.awt.Robot; + +public class XORClearRect extends Panel { + + public static void main(String args[]) throws Exception { + EventQueue.invokeAndWait(XORClearRect::createUI); + try { + Robot robot = new Robot(); + robot.waitForIdle(); + robot.delay(2000); + Point p = frame.getLocationOnScreen(); + int pix = robot.getPixelColor(p.x + 100, p.y + 100).getRGB(); + if (pix != Color.blue.getRGB()) { + throw new RuntimeException("Not blue"); + } + } finally { + if (frame != null) { + EventQueue.invokeAndWait(frame::dispose); + } + } + } + + static volatile Frame frame; + + static void createUI() { + frame = new Frame("XORClearRect"); + frame.setBackground(Color.blue); + XORClearRect xor = new XORClearRect(); + frame.add(xor); + frame.setSize(200,200); + frame.setVisible(true); + } + + public XORClearRect() { + setBackground(Color.blue); + } + + public void paint(Graphics g) { + g.setColor(Color.green); + g.drawLine(0,0,200,200); + g.drawLine(0,200,200,0); + g.setXORMode(Color.blue); + g.clearRect(50,50,100,100); //expecting the rectangle to be filled + // with the background color (blue) + } +} diff --git a/test/jdk/tools/launcher/MultipleJRERemoved.java b/test/jdk/tools/launcher/MultipleJRERemoved.java deleted file mode 100644 index 551ffc885f275..0000000000000 --- a/test/jdk/tools/launcher/MultipleJRERemoved.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (c) 2014, 2015, 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 - * @bug 8067437 - * @summary Verify Multiple JRE version support has been removed. - * @modules jdk.compiler - * jdk.zipfs - * @build TestHelper - * @run main MultipleJRERemoved - */ - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Files; -import java.util.*; -import java.util.jar.Attributes; -import java.util.jar.JarOutputStream; -import java.util.jar.Manifest; -import java.util.regex.Pattern; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import java.util.zip.ZipEntry; - -public class MultipleJRERemoved extends TestHelper { - - public static final String VERSION_JAR = "version.jar"; - public static final String PRINT_VERSION_CLASS = "PrintVersion"; - private final File javaFile = new File(PRINT_VERSION_CLASS + ".java"); - private final File clsFile = new File(PRINT_VERSION_CLASS + ".class"); - - private MultipleJRERemoved() { - } - - /** - * @param args the command line arguments - * @throws java.io.FileNotFoundException - */ - public static void main(String[] args) throws Exception { - MultipleJRERemoved a = new MultipleJRERemoved(); - a.run(args); - } - - /** - * Check all combinations of flags: "-version:", "-jre-restrict-search", "-jre-no-restrict-search". Test expects to see errors. - */ - @Test - public void allFlagCombinations() throws IOException { - final Pattern newLine = Pattern.compile("\n"); - createJar(Collections.emptyMap()); - - for (Flag flag1 : Flag.values()) { - for (Flag flag2 : Flag.values()) { - for (Flag flag3 : Flag.values()) { - List flags = Stream.of(flag1, flag2, flag3) - .filter(f -> !Flag.EMPTY.equals(f)) - .collect(Collectors.toList()); - - if (flags.size() == 0) continue; - - List flagValues = flags.stream() - .map(Flag::value) - .collect(Collectors.toList()); - - List errorMessages = flags.stream() - .map(Flag::errorMessage) - .flatMap(newLine::splitAsStream) - .collect(Collectors.toList()); - - List jarCmd = new ArrayList<>(); - jarCmd.add(javaCmd); - jarCmd.addAll(flagValues); - jarCmd.add("-jar"); - jarCmd.add("version.jar"); - - check(jarCmd, errorMessages); - - List cmd = new ArrayList<>(); - cmd.add(javaCmd); - cmd.addAll(flagValues); - cmd.add(PRINT_VERSION_CLASS); - - check(cmd, errorMessages); - } - } - } - } - - private void check(List cmd, List errorMessages) { - TestResult tr = doExec(cmd.toArray(new String[cmd.size()])); - tr.checkNegative(); - tr.isNotZeroOutput(); - errorMessages.forEach(tr::contains); - - if (!tr.testStatus) { - System.out.println(tr); - throw new RuntimeException("test case: failed\n" + cmd); - } - } - - /** - * Verifies that java -help output doesn't contain information about "mJRE" flags. - */ - @Test - public void javaHelp() { - TestResult tr = doExec(javaCmd, "-help"); - tr.checkPositive(); - tr.isNotZeroOutput(); - tr.notContains("-version:"); - tr.notContains("-jre-restrict-search"); - tr.notContains("-jre-no-restrict-search"); - tr.notContains("-no-jre-restrict-search"); //it's not a typo in flag name. - if (!tr.testStatus) { - System.out.println(tr); - throw new RuntimeException("Failed. java -help output contains obsolete flags.\n"); - } - } - - /** - * Verifies that java -jar version.jar output ignores "mJRE" manifest directives. - */ - @Test - public void manifestDirectives() throws IOException { - Map manifest = new TreeMap<>(); - manifest.put("JRE-Version", "1.8"); - manifest.put("JRE-Restrict-Search", "1.8"); - createJar(manifest); - - TestResult tr = doExec(javaCmd, "-jar", VERSION_JAR); - tr.checkPositive(); - tr.contains(System.getProperty("java.version")); - if (!tr.testStatus) { - System.out.println(tr); - throw new RuntimeException("Failed.\n"); - } - } - - private void emitFile() throws IOException { - List scr = new ArrayList<>(); - scr.add("public class PrintVersion {"); - scr.add(" public static void main(String... args) {"); - scr.add(" System.out.println(System.getProperty(\"java.version\"));"); - scr.add(" }"); - scr.add("}"); - createFile(javaFile, scr); - compile(javaFile.getName()); - } - - private void createJar(Map manifestAttributes) throws IOException { - emitFile(); - - Manifest manifest = new Manifest(); - final Attributes mainAttributes = manifest.getMainAttributes(); - mainAttributes.putValue("Manifest-Version", "1.0"); - mainAttributes.putValue("Main-Class", PRINT_VERSION_CLASS); - manifestAttributes.forEach(mainAttributes::putValue); - - try (JarOutputStream jar = new JarOutputStream(new FileOutputStream(VERSION_JAR), manifest)) { - jar.putNextEntry(new ZipEntry(PRINT_VERSION_CLASS + ".class")); - jar.write(Files.readAllBytes(clsFile.toPath())); - jar.closeEntry(); - } finally { - javaFile.delete(); - } - } - - private enum Flag { - EMPTY("", ""), - VERSION("-version:1.9", "Error: Specifying an alternate JDK/JRE version is no longer supported.\n" + - "The use of the flag '-version:' is no longer valid.\n" + - "Please download and execute the appropriate version."), - JRE_RESTRICT_SEARCH("-jre-restrict-search", "Error: Specifying an alternate JDK/JRE is no longer supported.\n" + - "The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid."), - JRE_NO_RESTRICT_SEARCH("-jre-no-restrict-search", "Error: Specifying an alternate JDK/JRE is no longer supported.\n" + - "The related flags -jre-restrict-search | -jre-no-restrict-search are also no longer valid."); - private final String flag; - private final String errorMessage; - - Flag(String flag, String errorMessage) { - this.flag = flag; - this.errorMessage = errorMessage; - } - - String value() { - return flag; - } - - String errorMessage() { - return errorMessage; - } - } -} diff --git a/test/jtreg-ext/requires/VMProps.java b/test/jtreg-ext/requires/VMProps.java index 795a658afa591..5aa703c5b26c2 100644 --- a/test/jtreg-ext/requires/VMProps.java +++ b/test/jtreg-ext/requires/VMProps.java @@ -386,6 +386,7 @@ protected void vmOptFinalFlags(SafeMap map) { vmOptFinalFlag(map, "EnableJVMCI"); vmOptFinalFlag(map, "EliminateAllocations"); vmOptFinalFlag(map, "UseCompressedOops"); + vmOptFinalFlag(map, "UseLargePages"); vmOptFinalFlag(map, "UseVectorizedMismatchIntrinsic"); vmOptFinalFlag(map, "ZGenerational"); } diff --git a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownCodeBlocks.java b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownCodeBlocks.java index 8f1c76b9e474d..dda8a76868e12 100644 --- a/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownCodeBlocks.java +++ b/test/langtools/jdk/javadoc/doclet/testMarkdown/TestMarkdownCodeBlocks.java @@ -486,4 +486,107 @@ public int hashCode() {
    NullPointerException - if other is null
    """); } + + @Test + public void testLeadingCodeBlock(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package p; + /// Leading code block + /// Lorum ipsum. + public class C { } + """); + + javadoc("-d", base.resolve("api").toString(), + "--no-platform-links", + "--source-path", src.toString(), + "p"); + checkExit(Exit.OK); + + // check first sentence is empty in package summary file + checkOutput("p/package-summary.html", true, + """ + +
     
    """); + + checkOutput("p/C.html", true, + """ +
    Leading code block
    +                    
    +

    Lorum ipsum.

    """); + + } + + @Test + public void testTrailingCodeBlock(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package p; + /// Lorum ipsum. + /// + /// Trailing code block + public class C { } + """); + + javadoc("-d", base.resolve("api").toString(), + "--no-platform-links", + "--source-path", src.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/C.html", true, + """ +

    Lorum ipsum.

    +
    Trailing code block
    +                    
    +
    """); + } + + // this example is derived from the test case in JDK-8338525 + @Test + public void testLeadingTrailingCodeBlockWithAnnotations(Path base) throws Exception { + Path src = base.resolve("src"); + tb.writeJavaFiles(src, + """ + package p; + public class C { + /// @Override + /// void m() {} + /// + /// Plain text + /// + /// @Override + /// void m() {} + public void m() {} + }"""); + + javadoc("-d", base.resolve("api").toString(), + "--no-platform-links", + "--source-path", src.toString(), + "p"); + checkExit(Exit.OK); + + checkOutput("p/C.html", true, + """ +
    void
    +
    m()
    +
     
    """, + """ +
    public \ + void m()
    +
    @Override
    +                    void m() {}
    +                    
    +

    Plain text

    +
    @Override
    +                    void m() {}
    +                    
    +
    """); + + } } diff --git a/test/langtools/tools/javac/doctree/DocCommentTester.java b/test/langtools/tools/javac/doctree/DocCommentTester.java index f14dde2e567cd..d418005745a0d 100644 --- a/test/langtools/tools/javac/doctree/DocCommentTester.java +++ b/test/langtools/tools/javac/doctree/DocCommentTester.java @@ -1043,8 +1043,9 @@ String normalize(String s, boolean isLineComment, boolean normalizeTags) { .replaceAll("(\\{@value\\s+[^}]+)\\s+(})", "$1$2"); } + // See comment in MarkdownTest for explanation of dummy and Override String normalizeFragment(String s) { - return s.replaceAll("\n[ \t]+@(?!([@*]|dummy))", "\n@"); + return s.replaceAll("\n[ \t]+@(?!([@*]|(dummy|Override)))", "\n@"); } int copyLiteral(String s, int start, StringBuilder sb) { diff --git a/test/langtools/tools/javac/doctree/MarkdownTest.java b/test/langtools/tools/javac/doctree/MarkdownTest.java index 8da9e6ed44c2e..3ec23076db9a8 100644 --- a/test/langtools/tools/javac/doctree/MarkdownTest.java +++ b/test/langtools/tools/javac/doctree/MarkdownTest.java @@ -40,6 +40,7 @@ * In the tests for code spans and code blocks, "@dummy" is used as a dummy inline * or block tag to verify that it is skipped as part of the code span or code block. * In other words, "@dummy" should appear as a literal part of the Markdown content. + * ("@Override" is also treated the same way, as a commonly found annotation.) * Conversely, standard tags are used to verify that a fragment of text is not being * skipped as a code span or code block. In other words, they should be recognized as tags * and not skipped as part of any Markdown content. @@ -409,6 +410,32 @@ void indentedCodeBlock_afterFencedCodeBlock() { } RawText[MARKDOWN, pos:85, .] block tags: empty ] +*/ + + /// Indented Code Block + /// Lorum ipsum. + void indentedCodeBlock_leading() { } +/* +DocComment[DOC_COMMENT, pos:0 + firstSentence: empty + body: 1 + RawText[MARKDOWN, pos:0, ____Indented_Code_Block|Lorum_ipsum.] + block tags: empty +] +*/ + + /// Lorum ipsum. + /// + /// Indented Code Block + void indentedCodeBlock_trailing() { } +/* +DocComment[DOC_COMMENT, pos:0 + firstSentence: 1 + RawText[MARKDOWN, pos:0, Lorum_ipsum.] + body: 1 + RawText[MARKDOWN, pos:18, Indented_Code_Block] + block tags: empty +] */ ///123. @@ -613,5 +640,24 @@ void indent8() { } ] */ +// The following test case is derived from the test case in JDK-8338525. + + /// @Override + /// void m() { } + /// + /// Plain text + /// + /// @Override + /// void m() { } + void leadingTrailingCodeBlocksWithAnnos() { } +/* +DocComment[DOC_COMMENT, pos:0 + firstSentence: empty + body: 1 + RawText[MARKDOWN, pos:0, ____@Override|____void_m()_{_}||...||____@Override|____void_m()_{_}] + block tags: empty +] +*/ + } diff --git a/test/langtools/tools/javac/tree/PrettyCharLiteral.java b/test/langtools/tools/javac/tree/PrettyCharLiteral.java new file mode 100644 index 0000000000000..eced3209607ce --- /dev/null +++ b/test/langtools/tools/javac/tree/PrettyCharLiteral.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024, Google LLC. 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 + * @bug 8340568 + * @summary Incorrect escaping of single quotes when pretty-printing character literals + * @modules jdk.compiler/com.sun.tools.javac.api + * jdk.compiler/com.sun.tools.javac.file + * jdk.compiler/com.sun.tools.javac.tree + * jdk.compiler/com.sun.tools.javac.util + */ + +import com.sun.tools.javac.file.JavacFileManager; +import com.sun.tools.javac.tree.Pretty; +import com.sun.tools.javac.tree.TreeMaker; +import com.sun.tools.javac.util.Context; + +import java.io.IOException; +import java.io.StringWriter; + +public class PrettyCharLiteral { + public static void main(String... args) throws Exception { + new PrettyCharLiteral().run(); + } + + private final TreeMaker make; + + private PrettyCharLiteral() { + Context ctx = new Context(); + JavacFileManager.preRegister(ctx); + this.make = TreeMaker.instance(ctx); + } + + void run() throws Exception { + assertEquals( + prettyPrintLiteral('\''), + """ + '\\'' + """.trim()); + assertEquals( + prettyPrintLiteral('"'), + """ + '"' + """.trim()); + assertEquals( + prettyPrintLiteral("'"), + """ + "'" + """.trim()); + assertEquals( + prettyPrintLiteral("\""), + """ + "\\"" + """.trim()); + } + + private void assertEquals(String actual, String expected) { + if (!actual.equals(expected)) { + throw new AssertionError("expected: " + expected + ", actual: " + actual); + } + } + + private String prettyPrintLiteral(Object value) throws IOException { + StringWriter sw = new StringWriter(); + new Pretty(sw, true).printExpr(make.Literal(value)); + return sw.toString(); + } +} diff --git a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java index 341b24c3e051a..9acff93aaca23 100644 --- a/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java +++ b/test/lib/jdk/test/lib/containers/systemd/SystemdTestUtils.java @@ -28,6 +28,7 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.nio.file.Path; +import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -92,19 +93,23 @@ public static OutputAnalyzer buildAndRunSystemdJava(SystemdRunOptions opts) thro try { return SystemdTestUtils.systemdRunJava(opts); } finally { - try { - if (files.memory() != null) { - Files.delete(files.memory()); - } - if (files.cpu() != null) { - Files.delete(files.cpu()); - } - if (files.sliceDotDDir() != null) { - FileUtils.deleteFileTreeUnchecked(files.sliceDotDDir()); - } - } catch (NoSuchFileException e) { - // ignore + cleanupFiles(files); + } + } + + private static void cleanupFiles(ResultFiles files) throws IOException { + try { + if (files.memory() != null) { + Files.delete(files.memory()); } + if (files.cpu() != null) { + Files.delete(files.cpu()); + } + if (files.sliceDotDDir() != null) { + FileUtils.deleteFileTreeUnchecked(files.sliceDotDDir()); + } + } catch (NoSuchFileException e) { + // ignore } } @@ -135,15 +140,23 @@ private static ResultFiles buildSystemdSlices(SystemdRunOptions runOpts) throws if (runOpts.hasSliceDLimit()) { String dirName = String.format("%s.slice.d", SLICE_NAMESPACE_PREFIX); sliceDotDDir = SYSTEMD_CONFIG_HOME.resolve(Path.of(dirName)); - Files.createDirectory(sliceDotDDir); + // Using createDirectories since we only need to ensure the directory + // exists. Ignore it if already existent. + Files.createDirectories(sliceDotDDir); if (runOpts.sliceDMemoryLimit != null) { Path memoryConfig = sliceDotDDir.resolve(Path.of(SLICE_D_MEM_CONFIG_FILE)); - Files.writeString(memoryConfig, getMemoryDSliceContent(runOpts)); + Files.writeString(memoryConfig, + getMemoryDSliceContent(runOpts), + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); } if (runOpts.sliceDCpuLimit != null) { Path cpuConfig = sliceDotDDir.resolve(Path.of(SLICE_D_CPU_CONFIG_FILE)); - Files.writeString(cpuConfig, getCPUDSliceContent(runOpts)); + Files.writeString(cpuConfig, + getCPUDSliceContent(runOpts), + StandardOpenOption.TRUNCATE_EXISTING, + StandardOpenOption.CREATE); } } @@ -159,7 +172,7 @@ private static ResultFiles buildSystemdSlices(SystemdRunOptions runOpts) throws throw new AssertionError("Failed to write systemd slice files"); } - systemdDaemonReload(cpu); + systemdDaemonReload(cpu, memory, sliceDotDDir); return new ResultFiles(memory, cpu, sliceDotDDir); } @@ -175,12 +188,25 @@ private static String sliceNameCpu(SystemdRunOptions runOpts) { return String.format("%s-cpu", slice); } - private static void systemdDaemonReload(Path cpu) throws Exception { + private static void systemdDaemonReload(Path cpu, Path memory, Path sliceDdir) throws Exception { List daemonReload = systemCtl(); daemonReload.add("daemon-reload"); if (execute(daemonReload).getExitValue() != 0) { - throw new AssertionError("Failed to reload systemd daemon"); + if (RUN_AS_USER) { + cleanupFiles(new ResultFiles(cpu, memory, sliceDdir)); + // When run as user the systemd user manager needs to be + // accessible and working. This is usually the case when + // connected via SSH or user login, but may not work for + // sessions set up via 'su ' or similar. + // In that case, 'systemctl --user status' usually doesn't + // work. There is no other option than skip the test. + String msg = "Service user@.service not properly configured. " + + "Skipping the test!"; + throw new SkippedException(msg); + } else { + throw new AssertionError("Failed to reload systemd daemon"); + } } } diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/Proxy/ProxyBench.java b/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyBench.java similarity index 100% rename from test/micro/org/openjdk/bench/java/lang/reflect/Proxy/ProxyBench.java rename to test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyBench.java diff --git a/test/micro/org/openjdk/bench/java/lang/reflect/Proxy/ProxyPerf.java b/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java similarity index 57% rename from test/micro/org/openjdk/bench/java/lang/reflect/Proxy/ProxyPerf.java rename to test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java index 22fe4d3ef28db..3393431730080 100644 --- a/test/micro/org/openjdk/bench/java/lang/reflect/Proxy/ProxyPerf.java +++ b/test/micro/org/openjdk/bench/java/lang/reflect/proxy/ProxyGeneratorBench.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2014, 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 @@ -26,7 +26,6 @@ import org.openjdk.jmh.annotations.Benchmark; import org.openjdk.jmh.annotations.BenchmarkMode; -import org.openjdk.jmh.annotations.CompilerControl; import org.openjdk.jmh.annotations.Fork; import org.openjdk.jmh.annotations.Measurement; import org.openjdk.jmh.annotations.Mode; @@ -36,37 +35,29 @@ import org.openjdk.jmh.annotations.State; import org.openjdk.jmh.annotations.Warmup; -import org.openjdk.jmh.infra.Blackhole; - import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.util.concurrent.TimeUnit; /** * Benchmark measuring java.lang.reflect.ProxyGenerator.generateProxyClass. * It bypasses the cache of proxies to measure the time to construct a proxy. */ -@Warmup(iterations = 5) -@Measurement(iterations = 10) -@Fork(value = 1) +@Warmup(iterations = 5, time = 2) +@Measurement(iterations = 5, time = 2) +@Fork(value = 1, jvmArgsPrepend = "--add-opens=java.base/java.lang.reflect=ALL-UNNAMED") @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Thread) -public class ProxyPerf { +public class ProxyGeneratorBench { /** * Sample results from a Dell T7610. * Benchmark Mode Cnt Score Error Units * ProxyPerf.genIntf_1 avgt 10 35325.428 +/- 780.459 ns/op - * ProxyPerf.genIntf_1_V49 avgt 10 34309.423 +/- 727.188 ns/op * ProxyPerf.genStringsIntf_3 avgt 10 46600.366 +/- 663.812 ns/op - * ProxyPerf.genStringsIntf_3_V49 avgt 10 45911.817 +/- 1598.536 ns/op * ProxyPerf.genZeroParams avgt 10 33245.048 +/- 437.988 ns/op - * ProxyPerf.genZeroParams_V49 avgt 10 32954.254 +/- 1041.932 ns/op - * ProxyPerf.getPrimsIntf_2 avgt 10 43987.819 +/- 837.443 ns/op - * ProxyPerf.getPrimsIntf_2_V49 avgt 10 42863.462 +/- 1193.480 ns/op + * ProxyPerf.genPrimsIntf_2 avgt 10 43987.819 +/- 837.443 ns/op */ public interface Intf_1 { @@ -84,7 +75,6 @@ public interface Intf_3 { public String m2String(String s1, String s2); } - private InvocationHandler handler; private ClassLoader classloader; private Method proxyGen; private Method proxyGenV49; @@ -92,19 +82,11 @@ public interface Intf_3 { @Setup public void setup() { try { - handler = (Object proxy, Method method, Object[] args) -> null; classloader = ClassLoader.getSystemClassLoader(); Class proxyGenClass = Class.forName("java.lang.reflect.ProxyGenerator"); proxyGen = proxyGenClass.getDeclaredMethod("generateProxyClass", ClassLoader.class, String.class, java.util.List.class, int.class); proxyGen.setAccessible(true); - - // Init access to the old Proxy generator - Class proxyGenClassV49 = Class.forName("java.lang.reflect.ProxyGenerator_v49"); - proxyGenV49 = proxyGenClassV49.getDeclaredMethod("generateProxyClass", - String.class, java.util.List.class, int.class); - proxyGenV49.setAccessible(true); - } catch (Exception ex) { ex.printStackTrace(); throw new RuntimeException("ProxyClass setup fails", ex); @@ -112,51 +94,35 @@ public void setup() { } @Benchmark - public void genZeroParams(Blackhole bh) throws Exception { + public Object genZeroParams() throws Exception { List> interfaces = List.of(Runnable.class); - bh.consume(proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1)); + return proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1); } @Benchmark - public void genIntf_1(Blackhole bh) throws Exception { + public Object genIntf_1() throws Exception { List> interfaces = List.of(Intf_1.class); - bh.consume(proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1)); + return proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1); } @Benchmark - public void getPrimsIntf_2(Blackhole bh) throws Exception { + public Object genPrimsIntf_2() throws Exception { List> interfaces = List.of(Intf_2.class); - bh.consume(proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1)); - } - @Benchmark - public void genStringsIntf_3(Blackhole bh) throws Exception { - List> interfaces = List.of(Intf_3.class); - bh.consume(proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1)); + return proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1); } - // Generate using the V49inal generator for comparison - @Benchmark - public void genZeroParams_V49(Blackhole bh) throws Exception { - List> interfaces = List.of(Runnable.class); - bh.consume(proxyGenV49.invoke(null, "ProxyImpl", interfaces, 1)); - } - - @Benchmark - public void genIntf_1_V49(Blackhole bh) throws Exception { - List> interfaces = List.of(Intf_1.class); - bh.consume(proxyGenV49.invoke(null, "ProxyImpl", interfaces, 1)); - } - - @Benchmark - public void getPrimsIntf_2_V49(Blackhole bh) throws Exception { - List> interfaces = List.of(Intf_2.class); - bh.consume(proxyGenV49.invoke(null, "ProxyImpl", interfaces, 1)); - } - @Benchmark - public void genStringsIntf_3_V49(Blackhole bh) throws Exception { + public Object genStringsIntf_3() throws Exception { List> interfaces = List.of(Intf_3.class); - bh.consume(proxyGenV49.invoke(null, "ProxyImpl", interfaces, 1)); + return proxyGen.invoke(null, classloader, "ProxyImpl", interfaces, 1); } + public static void main(String... args) throws Exception { + var benchmark = new ProxyGeneratorBench(); + benchmark.setup(); + benchmark.genZeroParams(); + benchmark.genIntf_1(); + benchmark.genPrimsIntf_2(); + benchmark.genStringsIntf_3(); + } } diff --git a/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java b/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java new file mode 100644 index 0000000000000..0f8bf0449af0b --- /dev/null +++ b/test/micro/org/openjdk/bench/jdk/classfile/ConstantPoolBuildingClassEntry.java @@ -0,0 +1,164 @@ +/* + * 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. + */ +package org.openjdk.bench.jdk.classfile; + +import java.lang.classfile.constantpool.ConstantPoolBuilder; +import java.lang.constant.ClassDesc; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.openjdk.jmh.annotations.*; +import org.openjdk.jmh.infra.Blackhole; + +import static java.lang.constant.ConstantDescs.*; + +import static org.openjdk.bench.jdk.classfile.TestConstants.*; + +/** + * Tests constant pool builder lookup performance for ClassEntry. + * Note that ClassEntry is available only for reference types. + */ +@Warmup(iterations = 3) +@Measurement(iterations = 5) +@OutputTimeUnit(TimeUnit.MILLISECONDS) +@BenchmarkMode(Mode.Throughput) +@Fork(value = 1, jvmArgsAppend = {"--enable-preview"}) +@State(Scope.Benchmark) +public class ConstantPoolBuildingClassEntry { + // JDK-8338546 + ConstantPoolBuilder builder; + List classDescs; + List nonIdenticalClassDescs; + List internalNames; + List nonDuplicateClassDescs; + List nonDuplicateInternalNames; + int size; + + @Setup(Level.Iteration) + public void setup() { + builder = ConstantPoolBuilder.of(); + // Note these can only be reference types, no primitives + classDescs = List.of( + CD_Byte, CD_Object, CD_Long.arrayType(), CD_String, CD_String, CD_Object, CD_Short, + CD_MethodHandle, CD_MethodHandle, CD_Object, CD_Character, CD_List, CD_ArrayList, + CD_List, CD_Set, CD_Integer, CD_Object.arrayType(), CD_Enum, CD_Object, CD_MethodHandles_Lookup, + CD_Long, CD_Set, CD_Object, CD_Character, CD_Integer, CD_System, CD_String, CD_String, + CD_CallSite, CD_Collection, CD_List, CD_Collection, CD_String, CD_int.arrayType() + ); + size = classDescs.size(); + nonIdenticalClassDescs = classDescs.stream().map(cd -> { + var ret = ClassDesc.ofDescriptor(new String(cd.descriptorString())); + ret.hashCode(); // pre-compute hash code for cd + return ret; + }).toList(); + internalNames = classDescs.stream().map(cd -> { + // also sets up builder + cd.hashCode(); // pre-computes hash code for cd + var ce = builder.classEntry(cd); + var ret = ce.name().stringValue(); + ret.hashCode(); // pre-computes hash code for stringValue + return ret; + }).toList(); + nonDuplicateClassDescs = List.copyOf(new LinkedHashSet<>(classDescs)); + nonDuplicateInternalNames = nonDuplicateClassDescs.stream().map(cd -> + builder.classEntry(cd).asInternalName()).toList(); + } + + // Copied from jdk.internal.classfile.impl.Util::toInternalName + // to reduce internal dependencies + public static String toInternalName(ClassDesc cd) { + var desc = cd.descriptorString(); + if (desc.charAt(0) == 'L') + return desc.substring(1, desc.length() - 1); + throw new IllegalArgumentException(desc); + } + + /** + * Looking up with identical ClassDesc objects. Happens in bytecode generators reusing + * constant CD_Xxx. + */ + @Benchmark + public void identicalLookup(Blackhole bh) { + for (var cd : classDescs) { + bh.consume(builder.classEntry(cd)); + } + } + + /** + * Looking up with non-identical ClassDesc objects. Happens in bytecode generators + * using ad-hoc Class.describeConstable().orElseThrow() or other parsed ClassDesc. + * Cannot use identity fast path compared to {@link #identicalLookup}. + */ + @Benchmark + public void nonIdenticalLookup(Blackhole bh) { + for (var cd : nonIdenticalClassDescs) { + bh.consume(builder.classEntry(cd)); + } + } + + /** + * Looking up with internal names. Closest to ASM behavior. + * Baseline for {@link #identicalLookup}. + */ + @Benchmark + public void internalNameLookup(Blackhole bh) { + for (var name : internalNames) { + bh.consume(builder.classEntry(builder.utf8Entry(name))); + } + } + + /** + * The default implementation provided by {@link ConstantPoolBuilder#classEntry(ClassDesc)}. + * Does substring so needs to rehash and has no caching, should be very slow. + */ + @Benchmark + public void oldStyleLookup(Blackhole bh) { + for (var cd : classDescs) { + var s = cd.isClassOrInterface() ? toInternalName(cd) : cd.descriptorString(); + bh.consume(builder.classEntry(builder.utf8Entry(s))); + } + } + + /** + * Measures performance of creating new class entries in new constant pools with symbols. + */ + @Benchmark + public void freshCreationWithDescs(Blackhole bh) { + var cp = ConstantPoolBuilder.of(); + for (var cd : nonDuplicateClassDescs) { + bh.consume(cp.classEntry(cd)); + } + } + + /** + * Measures performance of creating new class entries in new constant pools with internal names. + */ + @Benchmark + public void freshCreationWithInternalNames(Blackhole bh) { + var cp = ConstantPoolBuilder.of(); + for (var name : nonDuplicateInternalNames) { + bh.consume(cp.classEntry(cp.utf8Entry(name))); + } + } +}